From c17a176dec52cda7f19917ed94bd356ac687500e Mon Sep 17 00:00:00 2001 From: Sebastian Cabrera Samper Date: Sat, 8 Mar 2025 10:30:12 +0100 Subject: [PATCH 1/3] Changed: Folder restructuring Add: DI minimal configuration. Default value Add: DI ConnectionString configuration. Default value Add: DI - Tests Changed: Name DependencyInjectionExtension to DependencyInjection Changed: Name AzureStorageWrapperConfiguration to AzureStorageWrapperOptions Changed: Update Package Nuget. Changed: Readme. --- .editorconfig | 353 ++++++++++++++++++ ...rageWrapper.sln => AzureStorageWrapper.sln | 20 +- README.md | 85 ++++- res/images/icon.png | Bin 0 -> 16915 bytes res/images/poster.png | Bin 0 -> 41734 bytes .../AzureStorageWrapper.Tests.csproj | 30 ++ .../Should/BaseShould.cs | 0 .../Should/Delete/DeleteBlobShould.cs | 0 .../DependencyInjectionShould.cs | 103 +++++ .../Download/DownloadBlobReferenceShould.cs | 0 .../Download/DownloadBlobStreamShould.cs | 0 .../DownloadBlobUriVariationsShould.cs | 0 .../Should/Enumerate/EnumerateBlobsShould.cs | 0 .../Should/Upload/DiacriticsShould.cs | 0 .../Should/Upload/MetadataShould.cs | 0 .../Should/Upload/UploadBase64ImageShould.cs | 0 .../Should/Upload/UploadBase64Should.cs | 0 .../Should/Upload/UploadBytesShould.cs | 0 .../Upload/UploadInVirtualFolderShould.cs | 0 .../Should/Upload/UploadStreamShould.cs | 0 .../Sources/Images.cs | 0 src/AzureStorageWrapper.Tests/Startup.cs | 19 + .../AzureStorageWrapper.Tests.csproj | 28 -- .../AzureStorageWrapper.Tests/Startup.cs | 19 - .../AzureStorageWrapper.cs | 34 +- .../AzureStorageWrapper.csproj | 6 +- .../DependencyInjectionExtension.cs | 26 -- .../AzureStorageWrapperBase.cs | 0 ...ation.cs => AzureStorageWrapperOptions.cs} | 8 +- .../Commands/DeleteBlob.cs | 0 .../Commands/UploadBase64.cs | 0 .../Commands/UploadBlob.cs | 0 .../Commands/UploadBytes.cs | 0 .../Commands/UploadStream.cs | 0 .../DependencyInjection.cs | 35 ++ .../AzureStorageWrapperException.cs | 0 .../IAzureStorageWrapper.cs | 0 .../Queries/DownloadBlob.cs | 0 .../Queries/DownloadBlobReference.cs | 10 +- .../Queries/EnumerateBlobs.cs | 0 .../Queries/GetSasUri.cs | 10 +- .../Responses/Blob.cs | 0 .../Responses/BlobReference.cs | 0 .../Responses/BlobReferenceCollection.cs | 0 44 files changed, 663 insertions(+), 123 deletions(-) create mode 100644 .editorconfig rename src/AzureStorageWrapper/AzureStorageWrapper.sln => AzureStorageWrapper.sln (55%) create mode 100644 res/images/icon.png create mode 100644 res/images/poster.png create mode 100644 src/AzureStorageWrapper.Tests/AzureStorageWrapper.Tests.csproj rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/BaseShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Delete/DeleteBlobShould.cs (100%) create mode 100644 src/AzureStorageWrapper.Tests/Should/DependencyInjection/DependencyInjectionShould.cs rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Download/DownloadBlobReferenceShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Download/DownloadBlobStreamShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Download/DownloadBlobUriVariationsShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Enumerate/EnumerateBlobsShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Upload/DiacriticsShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Upload/MetadataShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Upload/UploadBase64ImageShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Upload/UploadBase64Should.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Upload/UploadBytesShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Upload/UploadInVirtualFolderShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Should/Upload/UploadStreamShould.cs (100%) rename src/{AzureStorageWrapper => }/AzureStorageWrapper.Tests/Sources/Images.cs (100%) create mode 100644 src/AzureStorageWrapper.Tests/Startup.cs delete mode 100644 src/AzureStorageWrapper/AzureStorageWrapper.Tests/AzureStorageWrapper.Tests.csproj delete mode 100644 src/AzureStorageWrapper/AzureStorageWrapper.Tests/Startup.cs rename src/AzureStorageWrapper/{AzureStorageWrapper => }/AzureStorageWrapper.cs (84%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/AzureStorageWrapper.csproj (92%) delete mode 100644 src/AzureStorageWrapper/AzureStorageWrapper/DependencyInjectionExtension.cs rename src/AzureStorageWrapper/{AzureStorageWrapper => }/AzureStorageWrapperBase.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper/AzureStorageWrapperConfiguration.cs => AzureStorageWrapperOptions.cs} (93%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Commands/DeleteBlob.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Commands/UploadBase64.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Commands/UploadBlob.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Commands/UploadBytes.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Commands/UploadStream.cs (100%) create mode 100644 src/AzureStorageWrapper/DependencyInjection.cs rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Exceptions/AzureStorageWrapperException.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/IAzureStorageWrapper.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Queries/DownloadBlob.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Queries/DownloadBlobReference.cs (73%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Queries/EnumerateBlobs.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Queries/GetSasUri.cs (72%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Responses/Blob.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Responses/BlobReference.cs (100%) rename src/AzureStorageWrapper/{AzureStorageWrapper => }/Responses/BlobReferenceCollection.cs (100%) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9aac13e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,353 @@ +# https://editorconfig.org/ +root=true + +[*] +charset = utf-8 +indent_style = space + +#Eliminar todos los espacios en blanco que preceden a los caracteres de nueva línea +trim_trailing_whitespace = true + +#Asegurarse de que el archivo termine con una nueva línea al guardar +insert_final_newline = true + +[{*.cpp,*.c,*.hpp,*.h,*.cs,*.razor}] +indent_size = 4 +tab_width = 4 + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 4 +tab_width = 4 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 4 +tab_width = 4 + +[*.json] +indent_size = 4 +tab_width = 4 + +[*.cs] +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false + +# Avoid "this." if not necessary +dotnet_style_qualification_for_field = false:refactoring +dotnet_style_qualification_for_property = false:refactoring +dotnet_style_qualification_for_method = false:refactoring +dotnet_style_qualification_for_event = false:refactoring + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Whitespace options +dotnet_style_allow_multiple_blank_lines_experimental = false + +# Non-private static fields are PascalCase +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style + +dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected +dotnet_naming_symbols.non_private_static_fields.required_modifiers = static + +dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case + +# Constants are PascalCase +dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants +dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style + +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_style.constant_style.capitalization = pascal_case + +# Instance fields are camelCase and start with _ +dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields +dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style + +dotnet_naming_symbols.instance_fields.applicable_kinds = field + +dotnet_naming_style.instance_field_style.capitalization = camel_case +dotnet_naming_style.instance_field_style.required_prefix = _ + +# Locals and parameters are camelCase +dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion +dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters +dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style + +dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local + +dotnet_naming_style.camel_case_style.capitalization = camel_case + +# Local functions are PascalCase +dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function + +dotnet_naming_style.local_function_style.capitalization = pascal_case + +# By default, name items with PascalCase +dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members +dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.all_members.applicable_kinds = * + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# RS0016: Only enable if API files are present +dotnet_public_api_analyzer.require_api_files = true + +# Dotnet code style settings: +[*.{cs}] + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:refactoring +dotnet_style_qualification_for_property = false:refactoring +dotnet_style_qualification_for_method = false:refactoring +dotnet_style_qualification_for_event = false:refactoring + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# Whitespace options +dotnet_style_allow_multiple_blank_lines_experimental = false + +# Non-private static fields are PascalCase +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style + +dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected +dotnet_naming_symbols.non_private_static_fields.required_modifiers = static + +dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case + +# Non-private readonly fields are PascalCase +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style + +dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected +dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly + +dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case + +# Constants are PascalCase +dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants +dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style + +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_style.constant_style.capitalization = pascal_case + +# Static fields are camelCase and start with s_ +dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields +dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style + +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.required_modifiers = static + +dotnet_naming_style.static_field_style.capitalization = camel_case +dotnet_naming_style.static_field_style.required_prefix = s_ + +# Instance fields are camelCase and start with _ +dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields +dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style + +dotnet_naming_symbols.instance_fields.applicable_kinds = field + +dotnet_naming_style.instance_field_style.capitalization = camel_case +dotnet_naming_style.instance_field_style.required_prefix = _ + +# Locals and parameters are camelCase +dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion +dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters +dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style + +dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local + +dotnet_naming_style.camel_case_style.capitalization = camel_case + +# Local functions are PascalCase +dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function + +dotnet_naming_style.local_function_style.capitalization = pascal_case + +# By default, name items with PascalCase +dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members +dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.all_members.applicable_kinds = * + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# RS0016: Only enable if API files are present +dotnet_public_api_analyzer.require_api_files = true + +# CSharp code style settings: + +[*.cs] +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + +# Whitespace options +csharp_style_allow_embedded_statements_on_same_line_experimental = false +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false + +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = do_not_ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Blocks are allowed +csharp_prefer_braces = true:silent +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = warning + +[src/{Compilers,ExpressionEvaluator,Scripting}/**Test**/*.{cs}] + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = none + +[src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs}] + +# IDE0011: Add braces +csharp_prefer_braces = when_multiline:warning +# NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201 +dotnet_diagnostic.IDE0011.severity = warning + +# IDE0040: Add accessibility modifiers +dotnet_diagnostic.IDE0040.severity = warning + +# IDE0052: Remove unread private member +dotnet_diagnostic.IDE0052.severity = warning + +# IDE0059: Unnecessary assignment to a value +dotnet_diagnostic.IDE0059.severity = warning + +# CA1012: Abstract types should not have public constructors +dotnet_diagnostic.CA1012.severity = warning + +# CA1822: Make member static +dotnet_diagnostic.CA1822.severity = warning + +# Prefer "var" everywhere +dotnet_diagnostic.IDE0007.severity = warning +csharp_style_var_for_built_in_types = true:warning +csharp_style_var_when_type_is_apparent = true:warning +csharp_style_var_elsewhere = true:warning + +# csharp_style_allow_embedded_statements_on_same_line_experimental +dotnet_diagnostic.IDE2001.severity = warning + +# csharp_style_allow_blank_lines_between_consecutive_braces_experimental +dotnet_diagnostic.IDE2002.severity = warning + +# csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental +dotnet_diagnostic.IDE2004.severity = warning + +# csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental +dotnet_diagnostic.IDE2005.severity = warning + +# csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental +dotnet_diagnostic.IDE2006.severity = warning + +[src/{VisualStudio}/**/*.{cs}] +# CA1822: Make member static +# There is a risk of accidentally breaking an internal API that partners rely on though IVT. +dotnet_code_quality.CA1822.api_surface = private \ No newline at end of file diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.sln b/AzureStorageWrapper.sln similarity index 55% rename from src/AzureStorageWrapper/AzureStorageWrapper.sln rename to AzureStorageWrapper.sln index 3cffa2b..65125f6 100644 --- a/src/AzureStorageWrapper/AzureStorageWrapper.sln +++ b/AzureStorageWrapper.sln @@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.6.33829.357 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "AzureStorageWrapper\AzureStorageWrapper.csproj", "{7B7A6304-3A42-4BCA-A7F3-61571EFB8D29}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{2589764D-0229-ED26-7A68-14C5BD399C78}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper.Tests", "AzureStorageWrapper.Tests\AzureStorageWrapper.Tests.csproj", "{31240418-FC87-432D-9D11-848CCE2C0B06}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper.Tests", "src\AzureStorageWrapper.Tests\AzureStorageWrapper.Tests.csproj", "{AE079CC8-4A2D-DEA4-B0CB-ABEA826CED09}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,14 +13,14 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7B7A6304-3A42-4BCA-A7F3-61571EFB8D29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7B7A6304-3A42-4BCA-A7F3-61571EFB8D29}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7B7A6304-3A42-4BCA-A7F3-61571EFB8D29}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7B7A6304-3A42-4BCA-A7F3-61571EFB8D29}.Release|Any CPU.Build.0 = Release|Any CPU - {31240418-FC87-432D-9D11-848CCE2C0B06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {31240418-FC87-432D-9D11-848CCE2C0B06}.Debug|Any CPU.Build.0 = Debug|Any CPU - {31240418-FC87-432D-9D11-848CCE2C0B06}.Release|Any CPU.ActiveCfg = Release|Any CPU - {31240418-FC87-432D-9D11-848CCE2C0B06}.Release|Any CPU.Build.0 = Release|Any CPU + {2589764D-0229-ED26-7A68-14C5BD399C78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2589764D-0229-ED26-7A68-14C5BD399C78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2589764D-0229-ED26-7A68-14C5BD399C78}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2589764D-0229-ED26-7A68-14C5BD399C78}.Release|Any CPU.Build.0 = Release|Any CPU + {AE079CC8-4A2D-DEA4-B0CB-ABEA826CED09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE079CC8-4A2D-DEA4-B0CB-ABEA826CED09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE079CC8-4A2D-DEA4-B0CB-ABEA826CED09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE079CC8-4A2D-DEA4-B0CB-ABEA826CED09}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/README.md b/README.md index 6f175d5..949e142 100644 --- a/README.md +++ b/README.md @@ -11,21 +11,93 @@ 📦 View package on [NuGet Gallery](https://www.nuget.org/packages/AzureStorageWrapper/) 📦 View package on [nuget.info](https://nuget.info/packages/AzureStorageWrapper) +## Supported framework + +* .Net Standard 2.0 +* .Net Standard 2.1 + +## Installation the package +Install the AzureStorageWrapper client library for .NET with NuGet: + +```dotnetcli +dotnet add package AzureStorageWrapper + ``` + +``` nuget +NuGet Install-Package AzureStorageWrapper -Version x.y.z +``` +This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of [Install-Package](https://learn.microsoft.com/es-es/nuget/reference/ps-reference/ps-ref-install-package). + +``` + +``` + For projects that support [PackageReference](https://learn.microsoft.com/es-es/nuget/consume-packages/package-references-in-project-files), copy this XML node into the project file to reference the package. + # Usage ## Dependency injection -To add **AzureStorageWrapper** to dependencies container, just use the method `AddAzureStorageWrapper(...)` +### File configuration +#### local.settings.json (Azure Function) +```json +{ + "IsEncrypted": false, + "Values": { + "AzureWebJobsStorage": "UseDevelopmentStorage=true", + "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", + + //Configuration StorageWrapper + StorageWrapper_ConnectionsString="..." //Is a configuration setting that contains the necessary information to connect to your Azure Storage account. Type: String. Recomended + StorageWrapper_MaxSasUriExpiration="..." //It sets the maximum duration for the Shared Access Signature (SAS) URI of an Azure Storage file. Type: int. Default: 600. Optional + StorageWrapper_DefaultSasUriExpiration="..." //It sets the default duration for the Shared Access Signature (SAS) URI of an Azure Storage file. Type: int. Default: 300. Optional + StorageWrapper_ReateContainerIfNotExists="..." //Determines whether the Azure Storage container should be automatically created if it does not already exist.Type: bool. Defult: true. Optional + } +} +``` +#### app.settings.json +```json +{ + //Configuration StorageWrapper + //Configuration StorageWrapper + StorageWrapper_ConnectionsString="..." //Is a configuration setting that contains the necessary information to connect to your Azure Storage account. Type: String. Recomended + StorageWrapper_MaxSasUriExpiration="..." //It sets the maximum duration for the Shared Access Signature (SAS) URI of an Azure Storage file. Type: int. Default: 600. Optional + StorageWrapper_DefaultSasUriExpiration="..." //It sets the default duration for the Shared Access Signature (SAS) URI of an Azure Storage file. Type: int. Default: 300. Optional + StorageWrapper_ReateContainerIfNotExists="..." //Determines whether the Azure Storage container should be automatically created if it does not already exist.Type: bool. Defult: true. Optional +} +``` + +> **Remember** that the variable names are suggested and you can change them according to your needs. + +### Minimal Configuration +To add **AzureStorageWrapper** to dependencies container. ```csharp var builder = WebApplication.CreateBuilder(args); -builder.Services.AddAzureStorageWrapper(configuration => +builder.Services.AddAzureStorageWrapper(); +``` +> **Warning:** You must configure the **StorageWrapper_ConnectionString** variable in the configuration file. + +### ConnectionString Configuration +To add **AzureStorageWrapper** to dependencies container, just use the method `AddAzureStorageWrapper(string connectionstring)` + +```csharp +var builder = WebApplication.CreateBuilder(args); +var connectionString = builder.Configuration["Connection_String"]; +builder.Services.AddAzureStorageWrapper(connectionString); +``` +### Configuration +To add **AzureStorageWrapper** to dependencies container, just use the method `AddAzureStorageWrapper(...)` + +```csharp +var builder = WebApplication.CreateBuilder(args); +var connectionString = builder.Configuration["Connection_String"]; +builder.Services.AddAzureStorageWrapper(options => { - configuration.ConnectionString = "azure-storage-connection-string"; - configuration.MaxSasUriExpiration = 600; - configuration.DefaultSasUriExpiration = 300; - configuration.CreateContainerIfNotExists = true; + options.ConnectionString = "azure-storage-connection-string"; + options.MaxSasUriExpiration = 600; + options.DefaultSasUriExpiration = 300; + options.CreateContainerIfNotExists = true; }); ``` @@ -291,3 +363,4 @@ If you like the project, you can consider making a donation at [ko-fi.com](https # Support You can contact me via Bluesky [@sergiobarriel.bsky.social](https://bsky.app/profile/sergiobarriel.bsky.social) or Twitter [@sergiobarriel](https://twitter.com/sergiobarriel), or if you have an [issue](https://github.com/sergiobarriel/AzureStorageWrapper/issues), you can open one 🙂 + diff --git a/res/images/icon.png b/res/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fea93fde6bd9b588a9961c0eb214193b4e59884a GIT binary patch literal 16915 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 PgS|A>bfL8>_VE7#BMBI} literal 0 HcmV?d00001 diff --git a/src/AzureStorageWrapper.Tests/AzureStorageWrapper.Tests.csproj b/src/AzureStorageWrapper.Tests/AzureStorageWrapper.Tests.csproj new file mode 100644 index 0000000..41ba6e3 --- /dev/null +++ b/src/AzureStorageWrapper.Tests/AzureStorageWrapper.Tests.csproj @@ -0,0 +1,30 @@ + + + + net9.0 + latest + enable + enable + false + 4125ba48-a89c-4eba-989b-dab2cbd677c4 + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/BaseShould.cs b/src/AzureStorageWrapper.Tests/Should/BaseShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/BaseShould.cs rename to src/AzureStorageWrapper.Tests/Should/BaseShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Delete/DeleteBlobShould.cs b/src/AzureStorageWrapper.Tests/Should/Delete/DeleteBlobShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Delete/DeleteBlobShould.cs rename to src/AzureStorageWrapper.Tests/Should/Delete/DeleteBlobShould.cs diff --git a/src/AzureStorageWrapper.Tests/Should/DependencyInjection/DependencyInjectionShould.cs b/src/AzureStorageWrapper.Tests/Should/DependencyInjection/DependencyInjectionShould.cs new file mode 100644 index 0000000..9207e3d --- /dev/null +++ b/src/AzureStorageWrapper.Tests/Should/DependencyInjection/DependencyInjectionShould.cs @@ -0,0 +1,103 @@ +using Microsoft.Extensions.DependencyInjection; +using Xunit; + +namespace AzureStorageWrapper.Tests.Should.DependencyInjection; + +public class DependencyInjectionTests +{ + [Fact] + public void AddAzureStorageWrapper_NoParameters_ShouldAddServices() + { + // Arrange + var serviceCollection = new ServiceCollection(); + Environment.SetEnvironmentVariable("StorageWrapper_ConnectionString", "UseDevelopmentStorage=true"); + + // Act + serviceCollection.AddAzureStorageWrapper(); + + // Assert + var serviceProvider = serviceCollection.BuildServiceProvider(); + var options = serviceProvider.GetService(); + var wrapper = serviceProvider.GetService(); + + Assert.NotNull(options); + Assert.NotNull(wrapper); + } + + [Fact] + public void AddAzureStorageWrapper_WithConnectionString_ShouldAddServices() + { + // Arrange + var serviceCollection = new ServiceCollection(); + var connectionString = "UseDevelopmentStorage=true"; + + // Act + serviceCollection.AddAzureStorageWrapper(connectionString); + + // Assert + var serviceProvider = serviceCollection.BuildServiceProvider(); + var options = serviceProvider.GetService(); + var wrapper = serviceProvider.GetService(); + + Assert.NotNull(options); + Assert.Equal(connectionString, options.ConnectionString); + Assert.NotNull(wrapper); + } + + [Fact] + public void AddAzureStorageWrapper_WithOptions_ShouldAddServices() + { + // Arrange + var serviceCollection = new ServiceCollection(); + var options = new AzureStorageWrapperOptions + { + ConnectionString = "UseDevelopmentStorage=true", + MaxSasUriExpiration = 600, + DefaultSasUriExpiration = 300, + CreateContainerIfNotExists = true + }; + + // Act + serviceCollection.AddAzureStorageWrapper(options); + + // Assert + var serviceProvider = serviceCollection.BuildServiceProvider(); + var resolvedOptions = serviceProvider.GetService(); + var wrapper = serviceProvider.GetService(); + + Assert.NotNull(resolvedOptions); + Assert.Equal(options.ConnectionString, resolvedOptions.ConnectionString); + Assert.Equal(options.MaxSasUriExpiration, resolvedOptions.MaxSasUriExpiration); + Assert.Equal(options.DefaultSasUriExpiration, resolvedOptions.DefaultSasUriExpiration); + Assert.Equal(options.CreateContainerIfNotExists, resolvedOptions.CreateContainerIfNotExists); + Assert.NotNull(wrapper); + } + + [Fact] + public void AddAzureStorageWrapper_WithOptionsAction_ShouldAddServices() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act + serviceCollection.AddAzureStorageWrapper(options => + { + options.ConnectionString = "UseDevelopmentStorage=true"; + options.MaxSasUriExpiration = 600; + options.DefaultSasUriExpiration = 300; + options.CreateContainerIfNotExists = true; + }); + + // Assert + var serviceProvider = serviceCollection.BuildServiceProvider(); + var options = serviceProvider.GetService(); + var wrapper = serviceProvider.GetService(); + + Assert.NotNull(options); + Assert.Equal("UseDevelopmentStorage=true", options.ConnectionString); + Assert.Equal(600, options.MaxSasUriExpiration); + Assert.Equal(300, options.DefaultSasUriExpiration); + Assert.True(options.CreateContainerIfNotExists); + Assert.NotNull(wrapper); + } +} diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Download/DownloadBlobReferenceShould.cs b/src/AzureStorageWrapper.Tests/Should/Download/DownloadBlobReferenceShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Download/DownloadBlobReferenceShould.cs rename to src/AzureStorageWrapper.Tests/Should/Download/DownloadBlobReferenceShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Download/DownloadBlobStreamShould.cs b/src/AzureStorageWrapper.Tests/Should/Download/DownloadBlobStreamShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Download/DownloadBlobStreamShould.cs rename to src/AzureStorageWrapper.Tests/Should/Download/DownloadBlobStreamShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Download/DownloadBlobUriVariationsShould.cs b/src/AzureStorageWrapper.Tests/Should/Download/DownloadBlobUriVariationsShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Download/DownloadBlobUriVariationsShould.cs rename to src/AzureStorageWrapper.Tests/Should/Download/DownloadBlobUriVariationsShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Enumerate/EnumerateBlobsShould.cs b/src/AzureStorageWrapper.Tests/Should/Enumerate/EnumerateBlobsShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Enumerate/EnumerateBlobsShould.cs rename to src/AzureStorageWrapper.Tests/Should/Enumerate/EnumerateBlobsShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/DiacriticsShould.cs b/src/AzureStorageWrapper.Tests/Should/Upload/DiacriticsShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/DiacriticsShould.cs rename to src/AzureStorageWrapper.Tests/Should/Upload/DiacriticsShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/MetadataShould.cs b/src/AzureStorageWrapper.Tests/Should/Upload/MetadataShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/MetadataShould.cs rename to src/AzureStorageWrapper.Tests/Should/Upload/MetadataShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadBase64ImageShould.cs b/src/AzureStorageWrapper.Tests/Should/Upload/UploadBase64ImageShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadBase64ImageShould.cs rename to src/AzureStorageWrapper.Tests/Should/Upload/UploadBase64ImageShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadBase64Should.cs b/src/AzureStorageWrapper.Tests/Should/Upload/UploadBase64Should.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadBase64Should.cs rename to src/AzureStorageWrapper.Tests/Should/Upload/UploadBase64Should.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadBytesShould.cs b/src/AzureStorageWrapper.Tests/Should/Upload/UploadBytesShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadBytesShould.cs rename to src/AzureStorageWrapper.Tests/Should/Upload/UploadBytesShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadInVirtualFolderShould.cs b/src/AzureStorageWrapper.Tests/Should/Upload/UploadInVirtualFolderShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadInVirtualFolderShould.cs rename to src/AzureStorageWrapper.Tests/Should/Upload/UploadInVirtualFolderShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadStreamShould.cs b/src/AzureStorageWrapper.Tests/Should/Upload/UploadStreamShould.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Should/Upload/UploadStreamShould.cs rename to src/AzureStorageWrapper.Tests/Should/Upload/UploadStreamShould.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Sources/Images.cs b/src/AzureStorageWrapper.Tests/Sources/Images.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper.Tests/Sources/Images.cs rename to src/AzureStorageWrapper.Tests/Sources/Images.cs diff --git a/src/AzureStorageWrapper.Tests/Startup.cs b/src/AzureStorageWrapper.Tests/Startup.cs new file mode 100644 index 0000000..f99f9aa --- /dev/null +++ b/src/AzureStorageWrapper.Tests/Startup.cs @@ -0,0 +1,19 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace AzureStorageWrapper.Tests +{ + public class Startup + { + public void ConfigureServices(IServiceCollection serviceCollection) + { + serviceCollection.AddAzureStorageWrapper(options => + { + options.ConnectionString = "UseDevelopmentStorage=true"; + options.MaxSasUriExpiration = 360; + options.DefaultSasUriExpiration = 360; + options.CreateContainerIfNotExists = true; + }); + } + } +} diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/AzureStorageWrapper.Tests.csproj b/src/AzureStorageWrapper/AzureStorageWrapper.Tests/AzureStorageWrapper.Tests.csproj deleted file mode 100644 index 7a60451..0000000 --- a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/AzureStorageWrapper.Tests.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - net8.0 - enable - enable - 4125ba48-a89c-4eba-989b-dab2cbd677c4 - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Startup.cs b/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Startup.cs deleted file mode 100644 index 3c4c40b..0000000 --- a/src/AzureStorageWrapper/AzureStorageWrapper.Tests/Startup.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; - -namespace AzureStorageWrapper.Tests -{ - public class Startup - { - public void ConfigureServices(IServiceCollection serviceCollection) - { - serviceCollection.AddAzureStorageWrapper(configuration => - { - configuration.ConnectionString = "UseDevelopmentStorage=true"; - configuration.MaxSasUriExpiration = 360; - configuration.DefaultSasUriExpiration = 360; - configuration.CreateContainerIfNotExists = true; - }); - } - } -} diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapper.cs b/src/AzureStorageWrapper/AzureStorageWrapper.cs similarity index 84% rename from src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapper.cs rename to src/AzureStorageWrapper/AzureStorageWrapper.cs index e2215e2..3cdb781 100644 --- a/src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapper.cs +++ b/src/AzureStorageWrapper/AzureStorageWrapper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -18,22 +18,22 @@ namespace AzureStorageWrapper { public class AzureStorageWrapper : AzureStorageWrapperBase, IAzureStorageWrapper { - private readonly AzureStorageWrapperConfiguration _configuration; + private readonly AzureStorageWrapperOptions _options; - public AzureStorageWrapper(AzureStorageWrapperConfiguration configuration) + public AzureStorageWrapper(AzureStorageWrapperOptions options) { - _configuration = configuration; + _options = options; } public async Task UploadBlobAsync(UploadBlob command) { command.Validate(); - var container = new BlobContainerClient(_configuration.ConnectionString, command.Container); + var container = new BlobContainerClient(_options.ConnectionString, command.Container); if (!await container.ExistsAsync()) { - if (_configuration.CreateContainerIfNotExists) await container.CreateIfNotExistsAsync(); + if (_options.CreateContainerIfNotExists) await container.CreateIfNotExistsAsync(); else throw new AzureStorageWrapperException($"container {command.Container} doesn't exists!"); } @@ -53,7 +53,7 @@ public async Task UploadBlobAsync(UploadBlob command) var sasUri = await GetSasUriAsync(new GetSasUri() { Uri = blob.Uri.AbsoluteUri, - ExpiresIn = _configuration.DefaultSasUriExpiration, + ExpiresIn = _options.DefaultSasUriExpiration, }); var blobReference = new BlobReference() @@ -64,7 +64,7 @@ public async Task UploadBlobAsync(UploadBlob command) Uri = blob.Uri.AbsoluteUri, SasUri = sasUri, Metadata = sanitizedDictionary, - SasExpires = DateTime.UtcNow.AddSeconds(_configuration.DefaultSasUriExpiration) + SasExpires = DateTime.UtcNow.AddSeconds(_options.DefaultSasUriExpiration) }; return blobReference; @@ -73,11 +73,11 @@ public async Task UploadBlobAsync(UploadBlob command) public async Task DownloadBlobReferenceAsync(DownloadBlobReference command) { - command.Validate(_configuration); + command.Validate(_options); var blob = new BlobClient(new Uri(command.Uri)); - var container = new BlobContainerClient(_configuration.ConnectionString, blob.BlobContainerName); + var container = new BlobContainerClient(_options.ConnectionString, blob.BlobContainerName); var blobClient = container.GetBlobClient(blob.Name); @@ -93,7 +93,7 @@ public async Task DownloadBlobReferenceAsync(DownloadBlobReferenc { Uri = command.Uri, ExpiresIn = command.ExpiresIn <= 0 - ? _configuration.DefaultSasUriExpiration + ? _options.DefaultSasUriExpiration : command.ExpiresIn, }), SasExpires = DateTime.MaxValue, @@ -108,7 +108,7 @@ public async Task DownloadBlobAsync(DownloadBlob command) var sasUri = await GetSasUriAsync(new GetSasUri() { Uri = command.Uri, - ExpiresIn = _configuration.DefaultSasUriExpiration, + ExpiresIn = _options.DefaultSasUriExpiration, }); using (var httpClient = new HttpClient()) @@ -135,7 +135,7 @@ public async Task DeleteBlobAsync(DeleteBlob command) var blob = new BlobClient(new Uri(command.Uri)); - var container = new BlobContainerClient(_configuration.ConnectionString, blob.BlobContainerName); + var container = new BlobContainerClient(_options.ConnectionString, blob.BlobContainerName); var blobClient = container.GetBlobClient(blob.Name); @@ -146,7 +146,7 @@ public async Task EnumerateBlobsAsync(EnumerateBlobs co { command.Validate(); - var container = new BlobContainerClient(_configuration.ConnectionString, command.Container); + var container = new BlobContainerClient(_options.ConnectionString, command.Container); var segment = container .GetBlobsAsync() @@ -165,7 +165,7 @@ public async Task EnumerateBlobsAsync(EnumerateBlobs co var blobReference = await DownloadBlobReferenceAsync(new DownloadBlobReference() { Uri = $"{container.Uri}/{item.Name}", - ExpiresIn = _configuration.DefaultSasUriExpiration + ExpiresIn = _options.DefaultSasUriExpiration }); references.Add(blobReference); @@ -186,11 +186,11 @@ public async Task EnumerateBlobsAsync(EnumerateBlobs co private async Task GetSasUriAsync(GetSasUri command) { - command.Validate(_configuration); + command.Validate(_options); var blob = new BlobClient(new Uri(command.Uri)); - var container = new BlobContainerClient(_configuration.ConnectionString, blob.BlobContainerName); + var container = new BlobContainerClient(_options.ConnectionString, blob.BlobContainerName); var blobClient = container.GetBlobClient(blob.Name); diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapper.csproj b/src/AzureStorageWrapper/AzureStorageWrapper.csproj similarity index 92% rename from src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapper.csproj rename to src/AzureStorageWrapper/AzureStorageWrapper.csproj index 6aeefe8..bd5dcdb 100644 --- a/src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapper.csproj +++ b/src/AzureStorageWrapper/AzureStorageWrapper.csproj @@ -19,15 +19,15 @@ - + True \ - + True \ - + True \ diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/DependencyInjectionExtension.cs b/src/AzureStorageWrapper/AzureStorageWrapper/DependencyInjectionExtension.cs deleted file mode 100644 index 9c00675..0000000 --- a/src/AzureStorageWrapper/AzureStorageWrapper/DependencyInjectionExtension.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace AzureStorageWrapper -{ - public static class DependencyInjectionExtension - { - public static void AddAzureStorageWrapper(this IServiceCollection serviceCollection, AzureStorageWrapperConfiguration configuration) - { - serviceCollection.AddSingleton(configuration); - - serviceCollection.AddSingleton(); - } - - public static void AddAzureStorageWrapper(this IServiceCollection serviceCollection, Action configurationAction) - { - var configuration = new AzureStorageWrapperConfiguration(); - - configurationAction(configuration); - - serviceCollection.AddSingleton(configuration); - - serviceCollection.AddSingleton(); - } - } -} diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapperBase.cs b/src/AzureStorageWrapper/AzureStorageWrapperBase.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapperBase.cs rename to src/AzureStorageWrapper/AzureStorageWrapperBase.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapperConfiguration.cs b/src/AzureStorageWrapper/AzureStorageWrapperOptions.cs similarity index 93% rename from src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapperConfiguration.cs rename to src/AzureStorageWrapper/AzureStorageWrapperOptions.cs index e9d3526..5b3103d 100644 --- a/src/AzureStorageWrapper/AzureStorageWrapper/AzureStorageWrapperConfiguration.cs +++ b/src/AzureStorageWrapper/AzureStorageWrapperOptions.cs @@ -1,10 +1,10 @@ -using AzureStorageWrapper.Exceptions; +using AzureStorageWrapper.Exceptions; namespace AzureStorageWrapper { - public class AzureStorageWrapperConfiguration + public class AzureStorageWrapperOptions { - public AzureStorageWrapperConfiguration() + public AzureStorageWrapperOptions() { MaxSasUriExpiration = int.MaxValue; } @@ -64,4 +64,4 @@ public bool CreateContainerIfNotExists set => _createContainerIfNotExists = value; } } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Commands/DeleteBlob.cs b/src/AzureStorageWrapper/Commands/DeleteBlob.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Commands/DeleteBlob.cs rename to src/AzureStorageWrapper/Commands/DeleteBlob.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Commands/UploadBase64.cs b/src/AzureStorageWrapper/Commands/UploadBase64.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Commands/UploadBase64.cs rename to src/AzureStorageWrapper/Commands/UploadBase64.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Commands/UploadBlob.cs b/src/AzureStorageWrapper/Commands/UploadBlob.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Commands/UploadBlob.cs rename to src/AzureStorageWrapper/Commands/UploadBlob.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Commands/UploadBytes.cs b/src/AzureStorageWrapper/Commands/UploadBytes.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Commands/UploadBytes.cs rename to src/AzureStorageWrapper/Commands/UploadBytes.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Commands/UploadStream.cs b/src/AzureStorageWrapper/Commands/UploadStream.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Commands/UploadStream.cs rename to src/AzureStorageWrapper/Commands/UploadStream.cs diff --git a/src/AzureStorageWrapper/DependencyInjection.cs b/src/AzureStorageWrapper/DependencyInjection.cs new file mode 100644 index 0000000..46cd9e0 --- /dev/null +++ b/src/AzureStorageWrapper/DependencyInjection.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.Extensions.DependencyInjection; + +namespace AzureStorageWrapper +{ + public static class DependencyInjection + { + public static IServiceCollection AddAzureStorageWrapper(this IServiceCollection serviceCollection) + => AddAzureStorageWrapper(serviceCollection, Environment.GetEnvironmentVariable("StorageWrapper_ConnectionString")); + + public static IServiceCollection AddAzureStorageWrapper(this IServiceCollection serviceCollection, string connectionstring) + => serviceCollection.AddAzureStorageWrapper(new AzureStorageWrapperOptions + { + ConnectionString = connectionstring, + MaxSasUriExpiration = 600, + DefaultSasUriExpiration = 300, + CreateContainerIfNotExists = true + }); + + public static IServiceCollection AddAzureStorageWrapper(this IServiceCollection serviceCollection, AzureStorageWrapperOptions options) + => serviceCollection.AddSingleton(options) + .AddSingleton() + ; + + public static IServiceCollection AddAzureStorageWrapper(this IServiceCollection serviceCollection, Action optionsAction) + { + var options = new AzureStorageWrapperOptions(); + + optionsAction(options); + + return serviceCollection.AddSingleton(options) + .AddSingleton(); + } + } +} diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Exceptions/AzureStorageWrapperException.cs b/src/AzureStorageWrapper/Exceptions/AzureStorageWrapperException.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Exceptions/AzureStorageWrapperException.cs rename to src/AzureStorageWrapper/Exceptions/AzureStorageWrapperException.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/IAzureStorageWrapper.cs b/src/AzureStorageWrapper/IAzureStorageWrapper.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/IAzureStorageWrapper.cs rename to src/AzureStorageWrapper/IAzureStorageWrapper.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Queries/DownloadBlob.cs b/src/AzureStorageWrapper/Queries/DownloadBlob.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Queries/DownloadBlob.cs rename to src/AzureStorageWrapper/Queries/DownloadBlob.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Queries/DownloadBlobReference.cs b/src/AzureStorageWrapper/Queries/DownloadBlobReference.cs similarity index 73% rename from src/AzureStorageWrapper/AzureStorageWrapper/Queries/DownloadBlobReference.cs rename to src/AzureStorageWrapper/Queries/DownloadBlobReference.cs index fd28e3b..45bee88 100644 --- a/src/AzureStorageWrapper/AzureStorageWrapper/Queries/DownloadBlobReference.cs +++ b/src/AzureStorageWrapper/Queries/DownloadBlobReference.cs @@ -1,4 +1,4 @@ -using System; +using System; using AzureStorageWrapper.Exceptions; namespace AzureStorageWrapper.Queries @@ -8,7 +8,7 @@ public class DownloadBlobReference public string Uri { get; set; } public int ExpiresIn { get; set; } - internal void Validate(AzureStorageWrapperConfiguration configuration) + internal void Validate(AzureStorageWrapperOptions options) { if (string.IsNullOrEmpty(Uri)) throw new AzureStorageWrapperException($"{nameof(Uri)} is empty!"); @@ -16,8 +16,8 @@ internal void Validate(AzureStorageWrapperConfiguration configuration) if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out var @_)) throw new AzureStorageWrapperException($"{nameof(Uri)} is not a valid absolute URI!"); - if (ExpiresIn > configuration.MaxSasUriExpiration) - throw new AzureStorageWrapperException($"{nameof(ExpiresIn)} should be lower than {configuration.MaxSasUriExpiration}"); + if (ExpiresIn > options.MaxSasUriExpiration) + throw new AzureStorageWrapperException($"{nameof(ExpiresIn)} should be lower than {options.MaxSasUriExpiration}"); } } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Queries/EnumerateBlobs.cs b/src/AzureStorageWrapper/Queries/EnumerateBlobs.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Queries/EnumerateBlobs.cs rename to src/AzureStorageWrapper/Queries/EnumerateBlobs.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Queries/GetSasUri.cs b/src/AzureStorageWrapper/Queries/GetSasUri.cs similarity index 72% rename from src/AzureStorageWrapper/AzureStorageWrapper/Queries/GetSasUri.cs rename to src/AzureStorageWrapper/Queries/GetSasUri.cs index 7e0b2de..12678d3 100644 --- a/src/AzureStorageWrapper/AzureStorageWrapper/Queries/GetSasUri.cs +++ b/src/AzureStorageWrapper/Queries/GetSasUri.cs @@ -1,4 +1,4 @@ -using System; +using System; using AzureStorageWrapper.Exceptions; namespace AzureStorageWrapper.Queries @@ -8,7 +8,7 @@ internal class GetSasUri public string Uri { get; set; } public int ExpiresIn { get; set; } - internal void Validate(AzureStorageWrapperConfiguration configuration) + internal void Validate(AzureStorageWrapperOptions options) { if (string.IsNullOrEmpty(Uri)) throw new AzureStorageWrapperException($"{nameof(Uri)} is empty!"); @@ -16,8 +16,8 @@ internal void Validate(AzureStorageWrapperConfiguration configuration) if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out var @_)) throw new AzureStorageWrapperException($"{nameof(Uri)} is not a valid absolute URI!"); - if (ExpiresIn > configuration.MaxSasUriExpiration) - throw new AzureStorageWrapperException($"{nameof(ExpiresIn)} should be lower than {configuration.MaxSasUriExpiration}"); + if (ExpiresIn > options.MaxSasUriExpiration) + throw new AzureStorageWrapperException($"{nameof(ExpiresIn)} should be lower than {options.MaxSasUriExpiration}"); } } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Responses/Blob.cs b/src/AzureStorageWrapper/Responses/Blob.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Responses/Blob.cs rename to src/AzureStorageWrapper/Responses/Blob.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Responses/BlobReference.cs b/src/AzureStorageWrapper/Responses/BlobReference.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Responses/BlobReference.cs rename to src/AzureStorageWrapper/Responses/BlobReference.cs diff --git a/src/AzureStorageWrapper/AzureStorageWrapper/Responses/BlobReferenceCollection.cs b/src/AzureStorageWrapper/Responses/BlobReferenceCollection.cs similarity index 100% rename from src/AzureStorageWrapper/AzureStorageWrapper/Responses/BlobReferenceCollection.cs rename to src/AzureStorageWrapper/Responses/BlobReferenceCollection.cs From e01745d8b7ba917600fcd0e13f4a9f1aadcd595b Mon Sep 17 00:00:00 2001 From: Sebastian Cabrera Samper Date: Sun, 9 Mar 2025 09:21:01 +0100 Subject: [PATCH 2/3] * **Add**: Add package EnsureThat * **Changed**: Solution updated with GuaranteeThat. --- src/AzureStorageWrapper.Tests/run-test.bat | 18 ++++++ src/AzureStorageWrapper.Tests/run-test.sh | 16 ++++++ .../AzureStorageWrapper.cs | 16 ++---- .../AzureStorageWrapper.csproj | 1 + .../Commands/DeleteBlob.cs | 26 +++++---- .../Commands/UploadBase64.cs | 6 +- .../Commands/UploadBlob.cs | 17 +++--- .../Commands/UploadBytes.cs | 12 ++-- .../Commands/UploadStream.cs | 14 ++--- .../AzureStorageWrapperException.cs | 7 +-- .../Extensions/EnsureThatExtension.cs | 55 +++++++++++++++++++ .../Queries/DownloadBlob.cs | 15 ++--- .../Queries/DownloadBlobReference.cs | 16 ++---- .../Queries/EnumerateBlobs.cs | 16 ++---- src/AzureStorageWrapper/Queries/GetSasUri.cs | 16 ++---- .../Responses/BlobReferenceCollection.cs | 6 +- 16 files changed, 155 insertions(+), 102 deletions(-) create mode 100644 src/AzureStorageWrapper.Tests/run-test.bat create mode 100644 src/AzureStorageWrapper.Tests/run-test.sh create mode 100644 src/AzureStorageWrapper/Extensions/EnsureThatExtension.cs diff --git a/src/AzureStorageWrapper.Tests/run-test.bat b/src/AzureStorageWrapper.Tests/run-test.bat new file mode 100644 index 0000000..0e1e40b --- /dev/null +++ b/src/AzureStorageWrapper.Tests/run-test.bat @@ -0,0 +1,18 @@ +@echo off + +REM Instructions to run this script: +REM 1. Make sure you have Azurite installed. You can install it using npm: +REM npm install -g azurite +REM 2. Make sure you have the .NET SDK installed and the `dotnet` command available in your PATH. +REM 3. Run the script by double-clicking it or executing it from the command line. + +echo Starting Azurite... +start /B azurite -s -l c:\azurite -d c:\azurite\debug.log + +REM Wait for a few seconds to ensure Azurite has started +timeout /t 5 /nobreak > NUL + +echo Running tests... +dotnet test + +pause diff --git a/src/AzureStorageWrapper.Tests/run-test.sh b/src/AzureStorageWrapper.Tests/run-test.sh new file mode 100644 index 0000000..f0939ee --- /dev/null +++ b/src/AzureStorageWrapper.Tests/run-test.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Instructions to run this script: +# 1. Make sure you have Azurite installed. You can install it using npm: +# npm install -g azurite +# 2. Make sure you have the .NET SDK installed and the `dotnet` command available in your PATH. +# 3. Give execution permissions to this file with the following command: +# chmod +x run-test.sh +# 4. Run the script with the following command: +# ./run-test.sh + +echo "Starting Azurite..." +azurite -s -l /path/to/azurite -d /path/to/azurite/debug.log & + +echo "Running tests..." +dotnet test diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.cs b/src/AzureStorageWrapper/AzureStorageWrapper.cs index 3cdb781..522e660 100644 --- a/src/AzureStorageWrapper/AzureStorageWrapper.cs +++ b/src/AzureStorageWrapper/AzureStorageWrapper.cs @@ -11,8 +11,10 @@ using Azure.Storage.Sas; using AzureStorageWrapper.Commands; using AzureStorageWrapper.Exceptions; +using AzureStorageWrapper.Extensions; using AzureStorageWrapper.Queries; using AzureStorageWrapper.Responses; +using EnsureThat; namespace AzureStorageWrapper { @@ -21,9 +23,7 @@ public class AzureStorageWrapper : AzureStorageWrapperBase, IAzureStorageWrapper private readonly AzureStorageWrapperOptions _options; public AzureStorageWrapper(AzureStorageWrapperOptions options) - { - _options = options; - } + => _options = options; public async Task UploadBlobAsync(UploadBlob command) { @@ -33,9 +33,8 @@ public async Task UploadBlobAsync(UploadBlob command) if (!await container.ExistsAsync()) { - if (_options.CreateContainerIfNotExists) await container.CreateIfNotExistsAsync(); - - else throw new AzureStorageWrapperException($"container {command.Container} doesn't exists!"); + Ensure.Bool.IsNotExistContainer(_options.CreateContainerIfNotExists, command.Container); + await container.CreateIfNotExistsAsync(); } var blobName = command.UseVirtualFolder @@ -115,10 +114,7 @@ public async Task DownloadBlobAsync(DownloadBlob command) { var response = await httpClient.GetAsync(sasUri); - if (!response.IsSuccessStatusCode) - { - throw new AzureStorageWrapperException($"something went wrong when downloading blob {command.Uri}"); - } + Ensure.Bool.IsTrue(response.IsSuccessStatusCode, $"something went wrong when downloading blob {command.Uri}"); var stream = await response.Content.ReadAsStreamAsync(); diff --git a/src/AzureStorageWrapper/AzureStorageWrapper.csproj b/src/AzureStorageWrapper/AzureStorageWrapper.csproj index bd5dcdb..30cbc8f 100644 --- a/src/AzureStorageWrapper/AzureStorageWrapper.csproj +++ b/src/AzureStorageWrapper/AzureStorageWrapper.csproj @@ -35,6 +35,7 @@ + diff --git a/src/AzureStorageWrapper/Commands/DeleteBlob.cs b/src/AzureStorageWrapper/Commands/DeleteBlob.cs index aeeb9f5..581eb0b 100644 --- a/src/AzureStorageWrapper/Commands/DeleteBlob.cs +++ b/src/AzureStorageWrapper/Commands/DeleteBlob.cs @@ -1,19 +1,21 @@ -using System; -using AzureStorageWrapper.Exceptions; +using AzureStorageWrapper.Extensions; +using EnsureThat; namespace AzureStorageWrapper.Commands { + /// + /// Represents a command to delete a blob. + /// public class DeleteBlob { + /// + /// Gets or sets the URI of the blob to be deleted. + /// public string Uri { get; set; } - - internal void Validate() - { - if (string.IsNullOrEmpty(Uri)) - throw new AzureStorageWrapperException($"{nameof(Uri)} is empty!"); - - if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out var @_)) - throw new AzureStorageWrapperException($"{nameof(Uri)} is not a valid absolute URI!"); - } + + /// + /// Validates the URI of the blob. + /// + internal void Validate() => Ensure.String.IsNotUri(Uri); } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/Commands/UploadBase64.cs b/src/AzureStorageWrapper/Commands/UploadBase64.cs index 12b3fbc..db6a710 100644 --- a/src/AzureStorageWrapper/Commands/UploadBase64.cs +++ b/src/AzureStorageWrapper/Commands/UploadBase64.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Text.RegularExpressions; using AzureStorageWrapper.Exceptions; @@ -22,10 +22,10 @@ public override Stream GetContent() var bytes = Convert.FromBase64String(Base64); return new MemoryStream(bytes); } - catch (Exception _) + catch (Exception) { throw new AzureStorageWrapperException("Invalid base64 string"); } } } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/Commands/UploadBlob.cs b/src/AzureStorageWrapper/Commands/UploadBlob.cs index bd347ea..e5da916 100644 --- a/src/AzureStorageWrapper/Commands/UploadBlob.cs +++ b/src/AzureStorageWrapper/Commands/UploadBlob.cs @@ -1,7 +1,9 @@ -using System; +using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; -using AzureStorageWrapper.Exceptions; +using AzureStorageWrapper.Extensions; +using EnsureThat; namespace AzureStorageWrapper.Commands { @@ -28,14 +30,9 @@ protected UploadBlob() internal void Validate() { - if (string.IsNullOrEmpty(Container)) - throw new AzureStorageWrapperException($"{nameof(Container)} is empty!"); - - if (string.IsNullOrEmpty(Name)) - throw new AzureStorageWrapperException($"{nameof(Name)} is empty!"); - - if (string.IsNullOrEmpty(Extension)) - throw new AzureStorageWrapperException($"{nameof(Extension)} is empty!"); + Ensure.String.IsNotNullOrEmptySW(Container); + Ensure.String.IsNotNullOrEmptySW(Name); + Ensure.String.IsNotNullOrEmptySW(Extension); } } } diff --git a/src/AzureStorageWrapper/Commands/UploadBytes.cs b/src/AzureStorageWrapper/Commands/UploadBytes.cs index 1a9925a..6e78796 100644 --- a/src/AzureStorageWrapper/Commands/UploadBytes.cs +++ b/src/AzureStorageWrapper/Commands/UploadBytes.cs @@ -1,5 +1,6 @@ -using System.IO; -using AzureStorageWrapper.Exceptions; +using System.IO; +using AzureStorageWrapper.Extensions; +using EnsureThat; namespace AzureStorageWrapper.Commands { @@ -7,11 +8,10 @@ public class UploadBytes : UploadBlob { public byte[] Bytes { get; set; } - public override Stream GetContent() + public override Stream GetContent() { - if (Bytes.Length == 0) throw new AzureStorageWrapperException($"{nameof(Bytes)} length is 0"); - + Ensure.Any.IsNotZero(Bytes); return new MemoryStream(Bytes); } } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/Commands/UploadStream.cs b/src/AzureStorageWrapper/Commands/UploadStream.cs index e1f838b..d64079a 100644 --- a/src/AzureStorageWrapper/Commands/UploadStream.cs +++ b/src/AzureStorageWrapper/Commands/UploadStream.cs @@ -1,5 +1,6 @@ -using System.IO; -using AzureStorageWrapper.Exceptions; +using System.IO; +using AzureStorageWrapper.Extensions; +using EnsureThat; namespace AzureStorageWrapper.Commands { @@ -7,11 +8,6 @@ public class UploadStream : UploadBlob { public Stream Stream { get; set; } - public override Stream GetContent() - { - if (Stream.Length == 0) throw new AzureStorageWrapperException($"{nameof(Stream)} length is 0"); - - return Stream; - } + public override Stream GetContent() => Ensure.Any.IsNotZero(Stream); } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/Exceptions/AzureStorageWrapperException.cs b/src/AzureStorageWrapper/Exceptions/AzureStorageWrapperException.cs index c21f492..3d92cb1 100644 --- a/src/AzureStorageWrapper/Exceptions/AzureStorageWrapperException.cs +++ b/src/AzureStorageWrapper/Exceptions/AzureStorageWrapperException.cs @@ -1,12 +1,9 @@ -using System; +using System; namespace AzureStorageWrapper.Exceptions { public class AzureStorageWrapperException : Exception { - public AzureStorageWrapperException(string message) : base(message) - { - - } + public AzureStorageWrapperException(string message) : base(message) { } } } diff --git a/src/AzureStorageWrapper/Extensions/EnsureThatExtension.cs b/src/AzureStorageWrapper/Extensions/EnsureThatExtension.cs new file mode 100644 index 0000000..28a6483 --- /dev/null +++ b/src/AzureStorageWrapper/Extensions/EnsureThatExtension.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; +using AzureStorageWrapper.Exceptions; +using EnsureThat; +using EnsureThat.Enforcers; + +namespace AzureStorageWrapper.Extensions +{ + public static class EnsureThatExtension + { + public static string IsNotNullOrEmptySW(this StringArg _, string value, [CallerMemberName] string paramName = null) + => Ensure.String.IsNotNullOrEmpty(value, paramName, opts => opts.WithException(new AzureStorageWrapperException($"{paramName} is empty!"))); + + public static string IsNotUri(this StringArg _, string value, [CallerMemberName] string paramName = null) + { + IsNotNullOrEmptySW(_, value, paramName); + return Uri.TryCreate(value, UriKind.Absolute, out var @__) + ? value + : throw new AzureStorageWrapperException($"{paramName} is not a valid absolute URI!"); + } + + + public static long IsLteSW(this ComparableArg _, long value, long limit, [CallerMemberName] string paramName = null) + => Ensure.Comparable.IsLte(value, limit, paramName, opts => opts.WithException(new AzureStorageWrapperException($"{paramName} should be lower than {limit}"))); + + + public static Stream IsNotZero(this AnyArg _, Stream value, [CallerMemberName] string paramName = null) + => value.Length > 0 + ? value + : throw new AzureStorageWrapperException($"{paramName} length is 0"); + public static byte[] IsNotZero(this AnyArg _, byte[] value, [CallerMemberName] string paramName = null) + => value.Length > 0 + ? value + : throw new AzureStorageWrapperException($"{paramName} length is 0"); + + + public static bool IsPaginateValid(this BoolArg _, bool paginate, int size, [CallerMemberName] string paramName = null) + { + if (paginate && size <= 0) + throw new AzureStorageWrapperException($"{nameof(size)} should be greater than zero when {nameof(paginate)} is true."); + return true; + } + public static bool IsPaginateValid(this BoolArg _, bool paginate, string ContinuationToken, [CallerMemberName] string paramName = null) + { + if (!paginate && !string.IsNullOrEmpty(ContinuationToken)) + throw new AzureStorageWrapperException($"{nameof(ContinuationToken)} should be greater than zero when {nameof(paginate)} is true."); + return true; + } + public static bool IsNotExistContainer(this BoolArg _, bool value,string container, [CallerMemberName] string paramName = null) + => Ensure.Bool.IsTrue(value, paramName, opts => opts.WithException(new AzureStorageWrapperException($"container {container} doesn't exists!"))); + public static bool IsTrue(this BoolArg _, bool value,string message) + => Ensure.Bool.IsTrue(value, null, opts => opts.WithException(new AzureStorageWrapperException(message))); + } +} diff --git a/src/AzureStorageWrapper/Queries/DownloadBlob.cs b/src/AzureStorageWrapper/Queries/DownloadBlob.cs index 4995520..7da3f38 100644 --- a/src/AzureStorageWrapper/Queries/DownloadBlob.cs +++ b/src/AzureStorageWrapper/Queries/DownloadBlob.cs @@ -1,5 +1,5 @@ -using System; -using AzureStorageWrapper.Exceptions; +using AzureStorageWrapper.Extensions; +using EnsureThat; namespace AzureStorageWrapper.Queries { @@ -7,13 +7,6 @@ public class DownloadBlob { public string Uri { get; set; } - internal void Validate() - { - if (string.IsNullOrEmpty(Uri)) - throw new AzureStorageWrapperException($"{nameof(Uri)} is empty!"); - - if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out var @_)) - throw new AzureStorageWrapperException($"{nameof(Uri)} is not a valid absolute URI!"); - } + internal void Validate() => Ensure.String.IsNotUri(Uri); } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/Queries/DownloadBlobReference.cs b/src/AzureStorageWrapper/Queries/DownloadBlobReference.cs index 45bee88..bdade3c 100644 --- a/src/AzureStorageWrapper/Queries/DownloadBlobReference.cs +++ b/src/AzureStorageWrapper/Queries/DownloadBlobReference.cs @@ -1,5 +1,5 @@ -using System; -using AzureStorageWrapper.Exceptions; +using AzureStorageWrapper.Extensions; +using EnsureThat; namespace AzureStorageWrapper.Queries { @@ -8,16 +8,10 @@ public class DownloadBlobReference public string Uri { get; set; } public int ExpiresIn { get; set; } - internal void Validate(AzureStorageWrapperOptions options) + internal void Validate(AzureStorageWrapperOptions option) { - if (string.IsNullOrEmpty(Uri)) - throw new AzureStorageWrapperException($"{nameof(Uri)} is empty!"); - - if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out var @_)) - throw new AzureStorageWrapperException($"{nameof(Uri)} is not a valid absolute URI!"); - - if (ExpiresIn > options.MaxSasUriExpiration) - throw new AzureStorageWrapperException($"{nameof(ExpiresIn)} should be lower than {options.MaxSasUriExpiration}"); + Ensure.String.IsNotUri(Uri); + Ensure.Comparable.IsLteSW(ExpiresIn, option.MaxSasUriExpiration); } } } diff --git a/src/AzureStorageWrapper/Queries/EnumerateBlobs.cs b/src/AzureStorageWrapper/Queries/EnumerateBlobs.cs index a0c803a..da3774a 100644 --- a/src/AzureStorageWrapper/Queries/EnumerateBlobs.cs +++ b/src/AzureStorageWrapper/Queries/EnumerateBlobs.cs @@ -1,4 +1,5 @@ -using AzureStorageWrapper.Exceptions; +using AzureStorageWrapper.Extensions; +using EnsureThat; namespace AzureStorageWrapper.Queries { @@ -11,14 +12,9 @@ public class EnumerateBlobs internal void Validate() { - if (string.IsNullOrEmpty(Container)) - throw new AzureStorageWrapperException($"{nameof(Container)} is empty!"); - - if (Paginate && Size <= 0) - throw new AzureStorageWrapperException($"{nameof(Size)} should be greater than zero when {nameof(Paginate)} is true."); - - if(!Paginate && !string.IsNullOrEmpty(ContinuationToken)) - throw new AzureStorageWrapperException($"{nameof(ContinuationToken)} should be empty when {nameof(Paginate)} is false."); + Ensure.String.IsNotNullOrEmptySW(Container); + Ensure.Bool.IsPaginateValid(Paginate, Size); + Ensure.Bool.IsPaginateValid(Paginate, ContinuationToken); } } -} \ No newline at end of file +} diff --git a/src/AzureStorageWrapper/Queries/GetSasUri.cs b/src/AzureStorageWrapper/Queries/GetSasUri.cs index 12678d3..99a38f7 100644 --- a/src/AzureStorageWrapper/Queries/GetSasUri.cs +++ b/src/AzureStorageWrapper/Queries/GetSasUri.cs @@ -1,5 +1,5 @@ -using System; -using AzureStorageWrapper.Exceptions; +using AzureStorageWrapper.Extensions; +using EnsureThat; namespace AzureStorageWrapper.Queries { @@ -8,16 +8,10 @@ internal class GetSasUri public string Uri { get; set; } public int ExpiresIn { get; set; } - internal void Validate(AzureStorageWrapperOptions options) + internal void Validate(AzureStorageWrapperOptions configuration) { - if (string.IsNullOrEmpty(Uri)) - throw new AzureStorageWrapperException($"{nameof(Uri)} is empty!"); - - if(!System.Uri.TryCreate(Uri, UriKind.Absolute, out var @_)) - throw new AzureStorageWrapperException($"{nameof(Uri)} is not a valid absolute URI!"); - - if (ExpiresIn > options.MaxSasUriExpiration) - throw new AzureStorageWrapperException($"{nameof(ExpiresIn)} should be lower than {options.MaxSasUriExpiration}"); + Ensure.String.IsNotUri(Uri); + Ensure.Comparable.IsLteSW(ExpiresIn, configuration.MaxSasUriExpiration); } } } diff --git a/src/AzureStorageWrapper/Responses/BlobReferenceCollection.cs b/src/AzureStorageWrapper/Responses/BlobReferenceCollection.cs index 8d2b289..4469f1f 100644 --- a/src/AzureStorageWrapper/Responses/BlobReferenceCollection.cs +++ b/src/AzureStorageWrapper/Responses/BlobReferenceCollection.cs @@ -5,11 +5,9 @@ namespace AzureStorageWrapper.Responses public class BlobReferenceCollection { public BlobReferenceCollection() - { - References = new List(); - } + => References = new List(); public IEnumerable References { get; set; } public string ContinuationToken { get; set; } } -} \ No newline at end of file +} From 2ac3117db7bcc91b9236b0ec9a4e4fd50618a5aa Mon Sep 17 00:00:00 2001 From: Sebastian Cabrera Samper Date: Mon, 10 Mar 2025 16:06:34 +0100 Subject: [PATCH 3/3] * **Add**: Samples Net Core ConsoleApp * **Add**: Samples Net Core Azure Funcion * **Add**: Samples NET Framework ConsoleApp --- README.md | 24 +- images/icon.png | Bin 16915 -> 0 bytes images/poster.png | Bin 41734 -> 0 bytes .../configuration/.gitignore | 264 ++++++++++++++++++ .../configuration/Function1.cs | 26 ++ .../configuration/Program.cs | 19 ++ .../Properties/launchSettings.json | 9 + .../Properties/serviceDependencies.json | 11 + .../Properties/serviceDependencies.local.json | 11 + .../configuration/host.json | 12 + .../configuration/samples.csproj | 44 +++ .../configuration/samples.sln | 31 ++ .../connectionstring-configuration/.gitignore | 264 ++++++++++++++++++ .../Function1.cs | 26 ++ .../connectionstring-configuration/Program.cs | 13 + .../Properties/launchSettings.json | 9 + .../Properties/serviceDependencies.json | 11 + .../Properties/serviceDependencies.local.json | 11 + .../connectionstring-configuration/host.json | 12 + .../samples.csproj | 44 +++ .../samples.sln | 31 ++ .../minimal-configuration/.gitignore | 264 ++++++++++++++++++ .../minimal-configuration/Function1.cs | 26 ++ .../minimal-configuration/Program.cs | 12 + .../Properties/launchSettings.json | 9 + .../Properties/serviceDependencies.json | 11 + .../Properties/serviceDependencies.local.json | 11 + .../minimal-configuration/host.json | 12 + .../minimal-configuration/samples.csproj | 44 +++ .../minimal-configuration/samples.sln | 31 ++ .../WithoutDependencyInjections/.gitignore | 264 ++++++++++++++++++ .../WithoutDependencyInjections/Function1.cs | 53 ++++ .../WithoutDependencyInjections/Program.cs | 9 + .../Properties/launchSettings.json | 9 + .../Properties/serviceDependencies.json | 11 + .../Properties/serviceDependencies.local.json | 11 + .../WithoutDependencyInjections/host.json | 12 + .../samples.csproj | 38 +++ .../WithoutDependencyInjections/samples.sln | 31 ++ .../configuration/Program.cs | 36 +++ .../configuration/app.settings.json | 3 + .../configuration/samples.csproj | 45 +++ .../configuration/samples.sln | 31 ++ .../connectionstring-configuration/Program.cs | 30 ++ .../app.settings.json | 3 + .../samples.csproj | 45 +++ .../samples.sln | 31 ++ .../minimal-configuration/Program.cs | 30 ++ .../minimal-configuration/app.settings.json | 3 + .../minimal-configuration/samples.csproj | 45 +++ .../minimal-configuration/samples.sln | 31 ++ .../WithoutDependencyInjections/Program.cs | 42 +++ .../samples.csproj | 33 +++ .../WithoutDependencyInjections/samples.sln | 31 ++ .../configuration/App.config | 41 +++ .../configuration/Program.cs | 45 +++ .../configuration/Properties/AssemblyInfo.cs | 33 +++ .../configuration/packages.config | 40 +++ .../configuration/samples.csproj | 211 ++++++++++++++ .../configuration/samples.sln | 31 ++ .../connectionstring-configuration/App.config | 41 +++ .../connectionstring-configuration/Program.cs | 39 +++ .../Properties/AssemblyInfo.cs | 33 +++ .../packages.config | 40 +++ .../samples.csproj | 211 ++++++++++++++ .../samples.sln | 31 ++ .../minimal-configuration/App.config | 41 +++ .../minimal-configuration/Program.cs | 39 +++ .../Properties/AssemblyInfo.cs | 33 +++ .../minimal-configuration/packages.config | 40 +++ .../minimal-configuration/samples.csproj | 211 ++++++++++++++ .../minimal-configuration/samples.sln | 31 ++ .../WithoutDependencyInjections/App.config | 38 +++ .../WithoutDependencyInjections/Program.cs | 47 ++++ .../Properties/AssemblyInfo.cs | 33 +++ .../packages.config | 40 +++ .../samples.csproj | 211 ++++++++++++++ .../WithoutDependencyInjections/samples.sln | 31 ++ samples/sharedcontent/AzuriteHelper.cs | 18 ++ samples/sharedcontent/ConsoleHelper.cs | 55 ++++ samples/sharedcontent/Delete_Blobs.cs | 31 ++ samples/sharedcontent/Download_Blobs.cs | 58 ++++ samples/sharedcontent/Enumerate_Blobs.cs | 78 ++++++ samples/sharedcontent/Samples_All.cs | 52 ++++ samples/sharedcontent/Upload_Blobs.cs | 84 ++++++ samples/sharedcontent/Virtual_Folders.cs | 62 ++++ samples/sharedcontent/run-azurite.bat | 11 + samples/sharedcontent/run-azurite.sh | 16 ++ 88 files changed, 4222 insertions(+), 3 deletions(-) delete mode 100644 images/icon.png delete mode 100644 images/poster.png create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/.gitignore create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/Function1.cs create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/Program.cs create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/launchSettings.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/serviceDependencies.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/serviceDependencies.local.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/host.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/samples.csproj create mode 100644 samples/dotnetcore/az-function/DependencyInjections/configuration/samples.sln create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/.gitignore create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Function1.cs create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Program.cs create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/launchSettings.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/serviceDependencies.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/serviceDependencies.local.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/host.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/samples.csproj create mode 100644 samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/samples.sln create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/.gitignore create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Function1.cs create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Program.cs create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/launchSettings.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/serviceDependencies.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/serviceDependencies.local.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/host.json create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/samples.csproj create mode 100644 samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/samples.sln create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/.gitignore create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/Function1.cs create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/Program.cs create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/launchSettings.json create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/serviceDependencies.json create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/serviceDependencies.local.json create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/host.json create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/samples.csproj create mode 100644 samples/dotnetcore/az-function/WithoutDependencyInjections/samples.sln create mode 100644 samples/dotnetcore/console/DependencyInjections/configuration/Program.cs create mode 100644 samples/dotnetcore/console/DependencyInjections/configuration/app.settings.json create mode 100644 samples/dotnetcore/console/DependencyInjections/configuration/samples.csproj create mode 100644 samples/dotnetcore/console/DependencyInjections/configuration/samples.sln create mode 100644 samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/Program.cs create mode 100644 samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/app.settings.json create mode 100644 samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/samples.csproj create mode 100644 samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/samples.sln create mode 100644 samples/dotnetcore/console/DependencyInjections/minimal-configuration/Program.cs create mode 100644 samples/dotnetcore/console/DependencyInjections/minimal-configuration/app.settings.json create mode 100644 samples/dotnetcore/console/DependencyInjections/minimal-configuration/samples.csproj create mode 100644 samples/dotnetcore/console/DependencyInjections/minimal-configuration/samples.sln create mode 100644 samples/dotnetcore/console/WithoutDependencyInjections/Program.cs create mode 100644 samples/dotnetcore/console/WithoutDependencyInjections/samples.csproj create mode 100644 samples/dotnetcore/console/WithoutDependencyInjections/samples.sln create mode 100644 samples/dotnetfw/console/DependencyInjections/configuration/App.config create mode 100644 samples/dotnetfw/console/DependencyInjections/configuration/Program.cs create mode 100644 samples/dotnetfw/console/DependencyInjections/configuration/Properties/AssemblyInfo.cs create mode 100644 samples/dotnetfw/console/DependencyInjections/configuration/packages.config create mode 100644 samples/dotnetfw/console/DependencyInjections/configuration/samples.csproj create mode 100644 samples/dotnetfw/console/DependencyInjections/configuration/samples.sln create mode 100644 samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/App.config create mode 100644 samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/Program.cs create mode 100644 samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/Properties/AssemblyInfo.cs create mode 100644 samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/packages.config create mode 100644 samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/samples.csproj create mode 100644 samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/samples.sln create mode 100644 samples/dotnetfw/console/DependencyInjections/minimal-configuration/App.config create mode 100644 samples/dotnetfw/console/DependencyInjections/minimal-configuration/Program.cs create mode 100644 samples/dotnetfw/console/DependencyInjections/minimal-configuration/Properties/AssemblyInfo.cs create mode 100644 samples/dotnetfw/console/DependencyInjections/minimal-configuration/packages.config create mode 100644 samples/dotnetfw/console/DependencyInjections/minimal-configuration/samples.csproj create mode 100644 samples/dotnetfw/console/DependencyInjections/minimal-configuration/samples.sln create mode 100644 samples/dotnetfw/console/WithoutDependencyInjections/App.config create mode 100644 samples/dotnetfw/console/WithoutDependencyInjections/Program.cs create mode 100644 samples/dotnetfw/console/WithoutDependencyInjections/Properties/AssemblyInfo.cs create mode 100644 samples/dotnetfw/console/WithoutDependencyInjections/packages.config create mode 100644 samples/dotnetfw/console/WithoutDependencyInjections/samples.csproj create mode 100644 samples/dotnetfw/console/WithoutDependencyInjections/samples.sln create mode 100644 samples/sharedcontent/AzuriteHelper.cs create mode 100644 samples/sharedcontent/ConsoleHelper.cs create mode 100644 samples/sharedcontent/Delete_Blobs.cs create mode 100644 samples/sharedcontent/Download_Blobs.cs create mode 100644 samples/sharedcontent/Enumerate_Blobs.cs create mode 100644 samples/sharedcontent/Samples_All.cs create mode 100644 samples/sharedcontent/Upload_Blobs.cs create mode 100644 samples/sharedcontent/Virtual_Folders.cs create mode 100644 samples/sharedcontent/run-azurite.bat create mode 100644 samples/sharedcontent/run-azurite.sh diff --git a/README.md b/README.md index 949e142..e708e12 100644 --- a/README.md +++ b/README.md @@ -256,7 +256,7 @@ To download a blob reference, you need to specify the `Uri`, which you should ha ```csharp var query = new DownloadBlobReference() { - Uri = "https://accountName.blob.core.windows.net/files/5a19306fc5014a4/hello.md" + Uri = "https://accountName.blob.core.windows.net/files/5a19306fc5014a4/hello.md", ExpiresIn = 60, }; @@ -309,7 +309,7 @@ var query = new EnumerateBlobs() Paginate = false }; -var response = await _azureStorageWrapper.EnumerateAllBlobsAsync(query); +var response = await _azureStorageWrapper.EnumerateBlobsAsync(query); ``` ### With pagination @@ -318,7 +318,7 @@ var response = await _azureStorageWrapper.EnumerateAllBlobsAsync(query); var query = new EnumerateBlobs() { Container = "files", - Paginate = true. + Paginate = true, Size = 10, }; @@ -348,6 +348,24 @@ var secondQuery = new EnumerateBlobs() var secondResponse = await _azureStorageWrapper.EnumerateBlobsAsync(secondQuery); ``` +# Samples + +| Framework | Type | Samples | +| --- | --- | --- | +| NET Core | Console |[Dependency Injections - Minimal Configuration](./samples/dotnetcore/console/DependencyInjections/minimal-configuration/) | +| NET Core | Console | [Dependency Injections - ConnectionString Configuration](./samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/) | +| NET Core | Console | [Dependency Injections - Configuration](./samples/dotnetcore/console/DependencyInjections/configuration/) | +| NET Core | Console | [Without Dependency Injections](./samples/dotnetcore/console/WithoutDependencyInjections/) | +| NET Core | Azure Function |[Dependency Injections - Minimal Configuration](./samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/) | +| NET Core | Azure Function | [Dependency Injections - ConnectionString Configuration](./samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/) | +| NET Core | Azure Function | [Dependency Injections - Configuration](./samples/dotnetcore/az-function/DependencyInjections/configuration/) | +| NET Core | Azure Function | [Without Dependency Injections](./samples/dotnetcore/az-function/WithoutDependencyInjections/) | +| NET FW | Console |[Dependency Injections - Minimal Configuration](./samples/dotnetfw/console/DependencyInjections/minimal-configuration/) | +| NET FW | Console | [Dependency Injections - ConnectionString Configuration](./samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/) | +| NET FW | Console | [Dependency Injections - Configuration](./samples/dotnetfw/console/DependencyInjections/configuration/) | +| NET FW | Console | [Without Dependency Injections](./samples/dotnetfw/console/WithoutDependencyInjections/) | + + # Contributors / Collaborators These individuals have contributed to the repository through suggestions, error corrections, or by opening issues. Thanks 😊 diff --git a/images/icon.png b/images/icon.png deleted file mode 100644 index fea93fde6bd9b588a9961c0eb214193b4e59884a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16915 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 PgS|A>bfL8>_VE7#BMBI} diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/.gitignore b/samples/dotnetcore/az-function/DependencyInjections/configuration/.gitignore new file mode 100644 index 0000000..ff5b00c --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/Function1.cs b/samples/dotnetcore/az-function/DependencyInjections/configuration/Function1.cs new file mode 100644 index 0000000..f7f4106 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/Function1.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; + +namespace samples +{ + public class Function1 + { + private readonly ILogger _logger; + private readonly Samples_All _samplesAll; + public Function1(ILogger logger, Samples_All samplesAll) + { + _logger = logger; + _samplesAll = samplesAll; + } + + [Function("Function1")] + public async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) + { + await _samplesAll.RunAsync(); + return new OkObjectResult("FIN"); + } + } +} diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/Program.cs b/samples/dotnetcore/az-function/DependencyInjections/configuration/Program.cs new file mode 100644 index 0000000..2c5a9ba --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/Program.cs @@ -0,0 +1,19 @@ +using Microsoft.Azure.Functions.Worker.Builder; +using Microsoft.Extensions.Hosting; +using AzureStorageWrapper; +using samples; + +var builder = FunctionsApplication.CreateBuilder(args) + .ConfigureFunctionsWebApplication(); +builder.Services.AddExample_All();//Configuration Example_All + +var connectionString = builder.Configuration["AzureStorageWrapper_ConnectionString"]; +builder.Services.AddAzureStorageWrapper(options => +{ + options.ConnectionString = connectionString; + options.MaxSasUriExpiration = 600; + options.DefaultSasUriExpiration = 300; + options.CreateContainerIfNotExists = true; +});//Configuration AzureStorageWrapper + +builder.Build().Run(); diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/launchSettings.json b/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/launchSettings.json new file mode 100644 index 0000000..996be21 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "samples": { + "commandName": "Project", + "commandLineArgs": "--port 7276", + "launchBrowser": false + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/serviceDependencies.json b/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/serviceDependencies.json new file mode 100644 index 0000000..df4dcc9 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/serviceDependencies.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights" + }, + "storage1": { + "type": "storage", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/serviceDependencies.local.json b/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..b804a28 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/Properties/serviceDependencies.local.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights.sdk" + }, + "storage1": { + "type": "storage.emulator", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/host.json b/samples/dotnetcore/az-function/DependencyInjections/configuration/host.json new file mode 100644 index 0000000..ee5cf5f --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/host.json @@ -0,0 +1,12 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + }, + "enableLiveMetricsFilters": true + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/samples.csproj b/samples/dotnetcore/az-function/DependencyInjections/configuration/samples.csproj new file mode 100644 index 0000000..e3231af --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/samples.csproj @@ -0,0 +1,44 @@ + + + net9.0 + v4 + Exe + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + + + \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/configuration/samples.sln b/samples/dotnetcore/az-function/DependencyInjections/configuration/samples.sln new file mode 100644 index 0000000..ef958c8 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{E4872347-A244-1216-9685-2A128BFF7897}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E12D5190-C961-4C03-82B0-F8EF22646C23} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/.gitignore b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/.gitignore new file mode 100644 index 0000000..ff5b00c --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Function1.cs b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Function1.cs new file mode 100644 index 0000000..f7f4106 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Function1.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; + +namespace samples +{ + public class Function1 + { + private readonly ILogger _logger; + private readonly Samples_All _samplesAll; + public Function1(ILogger logger, Samples_All samplesAll) + { + _logger = logger; + _samplesAll = samplesAll; + } + + [Function("Function1")] + public async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) + { + await _samplesAll.RunAsync(); + return new OkObjectResult("FIN"); + } + } +} diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Program.cs b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Program.cs new file mode 100644 index 0000000..907149a --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Program.cs @@ -0,0 +1,13 @@ +using Microsoft.Azure.Functions.Worker.Builder; +using Microsoft.Extensions.Hosting; +using AzureStorageWrapper; +using samples; + +var builder = FunctionsApplication.CreateBuilder(args) + .ConfigureFunctionsWebApplication(); +builder.Services.AddExample_All();//Configuration Example_All + +var configurationString = builder.Configuration["AzureStorageWrapper_ConnectionString"]; +builder.Services.AddAzureStorageWrapper(configurationString);//Configuration AzureStorageWrapper + +builder.Build().Run(); diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/launchSettings.json b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/launchSettings.json new file mode 100644 index 0000000..996be21 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "samples": { + "commandName": "Project", + "commandLineArgs": "--port 7276", + "launchBrowser": false + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/serviceDependencies.json b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/serviceDependencies.json new file mode 100644 index 0000000..df4dcc9 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/serviceDependencies.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights" + }, + "storage1": { + "type": "storage", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/serviceDependencies.local.json b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..b804a28 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/Properties/serviceDependencies.local.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights.sdk" + }, + "storage1": { + "type": "storage.emulator", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/host.json b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/host.json new file mode 100644 index 0000000..ee5cf5f --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/host.json @@ -0,0 +1,12 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + }, + "enableLiveMetricsFilters": true + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/samples.csproj b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/samples.csproj new file mode 100644 index 0000000..e3231af --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/samples.csproj @@ -0,0 +1,44 @@ + + + net9.0 + v4 + Exe + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + + + \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/samples.sln b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/samples.sln new file mode 100644 index 0000000..ef958c8 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/connectionstring-configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{E4872347-A244-1216-9685-2A128BFF7897}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E12D5190-C961-4C03-82B0-F8EF22646C23} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/.gitignore b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/.gitignore new file mode 100644 index 0000000..ff5b00c --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Function1.cs b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Function1.cs new file mode 100644 index 0000000..f7f4106 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Function1.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; + +namespace samples +{ + public class Function1 + { + private readonly ILogger _logger; + private readonly Samples_All _samplesAll; + public Function1(ILogger logger, Samples_All samplesAll) + { + _logger = logger; + _samplesAll = samplesAll; + } + + [Function("Function1")] + public async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) + { + await _samplesAll.RunAsync(); + return new OkObjectResult("FIN"); + } + } +} diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Program.cs b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Program.cs new file mode 100644 index 0000000..8fe544e --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Program.cs @@ -0,0 +1,12 @@ +using Microsoft.Azure.Functions.Worker.Builder; +using Microsoft.Extensions.Hosting; +using AzureStorageWrapper; +using samples; + +var builder = FunctionsApplication.CreateBuilder(args) + .ConfigureFunctionsWebApplication(); +builder.Services.AddExample_All();//Configuration Example_All + +builder.Services.AddAzureStorageWrapper();//Configuration AzureStorageWrapper + +builder.Build().Run(); diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/launchSettings.json b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/launchSettings.json new file mode 100644 index 0000000..996be21 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "samples": { + "commandName": "Project", + "commandLineArgs": "--port 7276", + "launchBrowser": false + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/serviceDependencies.json b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/serviceDependencies.json new file mode 100644 index 0000000..df4dcc9 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/serviceDependencies.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights" + }, + "storage1": { + "type": "storage", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/serviceDependencies.local.json b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..b804a28 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/Properties/serviceDependencies.local.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights.sdk" + }, + "storage1": { + "type": "storage.emulator", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/host.json b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/host.json new file mode 100644 index 0000000..ee5cf5f --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/host.json @@ -0,0 +1,12 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + }, + "enableLiveMetricsFilters": true + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/samples.csproj b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/samples.csproj new file mode 100644 index 0000000..e3231af --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/samples.csproj @@ -0,0 +1,44 @@ + + + net9.0 + v4 + Exe + enable + enable + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + + + \ No newline at end of file diff --git a/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/samples.sln b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/samples.sln new file mode 100644 index 0000000..ef958c8 --- /dev/null +++ b/samples/dotnetcore/az-function/DependencyInjections/minimal-configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{E4872347-A244-1216-9685-2A128BFF7897}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E12D5190-C961-4C03-82B0-F8EF22646C23} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/.gitignore b/samples/dotnetcore/az-function/WithoutDependencyInjections/.gitignore new file mode 100644 index 0000000..ff5b00c --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/Function1.cs b/samples/dotnetcore/az-function/WithoutDependencyInjections/Function1.cs new file mode 100644 index 0000000..6b29138 --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/Function1.cs @@ -0,0 +1,53 @@ +using AzureStorageWrapper.Commands; +using AzureStorageWrapper; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.Functions.Worker; +using Microsoft.Extensions.Logging; +using samples.Helpers; + +namespace samples +{ + public class Function1 + { + private readonly ILogger _logger; + public Function1(ILogger logger) + { + _logger = logger; + } + + [Function("Function1")] + public async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req) + { + var options = new AzureStorageWrapperOptions + { + ConnectionString = "UseDevelopmentStorage=true", + MaxSasUriExpiration = 600, + DefaultSasUriExpiration = 300, + CreateContainerIfNotExists = true, + }; + var azureStorageWrapper = new AzureStorageWrapper.AzureStorageWrapper(options); + + + #region Upload Blobs In Bytes + ConsoleHelper.Start("Upload in Bytes"); + var bytes = Convert.FromBase64String("SGVsbG8g8J+Zgg=="); + + var command = new UploadBytes() + { + Bytes = bytes, + Container = "files", + Name = "hello", + Extension = "md", + Metadata = new Dictionary() { { "key", "value" } } + }; + + var response = await azureStorageWrapper.UploadBlobAsync(command); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Upload in Base64"); + #endregion + + return new OkObjectResult("FIN"); + } + } +} diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/Program.cs b/samples/dotnetcore/az-function/WithoutDependencyInjections/Program.cs new file mode 100644 index 0000000..2ef5201 --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/Program.cs @@ -0,0 +1,9 @@ +using Microsoft.Azure.Functions.Worker.Builder; +using Microsoft.Extensions.Hosting; +using AzureStorageWrapper; +using samples; + +var builder = FunctionsApplication.CreateBuilder(args) + .ConfigureFunctionsWebApplication(); + +builder.Build().Run(); diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/launchSettings.json b/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/launchSettings.json new file mode 100644 index 0000000..996be21 --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/launchSettings.json @@ -0,0 +1,9 @@ +{ + "profiles": { + "samples": { + "commandName": "Project", + "commandLineArgs": "--port 7276", + "launchBrowser": false + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/serviceDependencies.json b/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/serviceDependencies.json new file mode 100644 index 0000000..df4dcc9 --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/serviceDependencies.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights" + }, + "storage1": { + "type": "storage", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/serviceDependencies.local.json b/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..b804a28 --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/Properties/serviceDependencies.local.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "appInsights1": { + "type": "appInsights.sdk" + }, + "storage1": { + "type": "storage.emulator", + "connectionId": "AzureWebJobsStorage" + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/host.json b/samples/dotnetcore/az-function/WithoutDependencyInjections/host.json new file mode 100644 index 0000000..ee5cf5f --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/host.json @@ -0,0 +1,12 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + }, + "enableLiveMetricsFilters": true + } + } +} \ No newline at end of file diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/samples.csproj b/samples/dotnetcore/az-function/WithoutDependencyInjections/samples.csproj new file mode 100644 index 0000000..8928aae --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/samples.csproj @@ -0,0 +1,38 @@ + + + net9.0 + v4 + Exe + enable + enable + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + + + \ No newline at end of file diff --git a/samples/dotnetcore/az-function/WithoutDependencyInjections/samples.sln b/samples/dotnetcore/az-function/WithoutDependencyInjections/samples.sln new file mode 100644 index 0000000..6fa460a --- /dev/null +++ b/samples/dotnetcore/az-function/WithoutDependencyInjections/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{E4872347-A244-1216-9685-2A128BFF7897}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{B73B6239-54A0-7B08-257C-59BFD8269DD3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.Build.0 = Release|Any CPU + {B73B6239-54A0-7B08-257C-59BFD8269DD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B73B6239-54A0-7B08-257C-59BFD8269DD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B73B6239-54A0-7B08-257C-59BFD8269DD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B73B6239-54A0-7B08-257C-59BFD8269DD3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E12D5190-C961-4C03-82B0-F8EF22646C23} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetcore/console/DependencyInjections/configuration/Program.cs b/samples/dotnetcore/console/DependencyInjections/configuration/Program.cs new file mode 100644 index 0000000..e137e9e --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/configuration/Program.cs @@ -0,0 +1,36 @@ +using AzureStorageWrapper; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using samples; + + +AzuriteHelper.Start();// Starts the Azurite process by executing the run-azurite.bat file + +var host = Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((context, config) => + { + config.AddJsonFile("app.settings.json", optional: false, reloadOnChange: true);// Add app.settings.json to the configuration + + }) + .ConfigureServices((context, services) => { + var connectionString = context.Configuration["StorageWrapper_ConnectionString"];// Set the StorageWrapper_ConnectionString string in the environment variables + services.AddAzureStorageWrapper(options => + { + options.ConnectionString = connectionString; + options.MaxSasUriExpiration = 600; + options.DefaultSasUriExpiration = 300; + options.CreateContainerIfNotExists = true; + });//Configuration AzureStorageWrapper + + services.AddExample_All();//Configuration Example_All + + }) + .Build(); + +var example_All = host.Services.GetService(); +await example_All.RunAsync();// Run the example_All service + +Console.WriteLine("Press any key to exit"); +Console.ReadKey(); + diff --git a/samples/dotnetcore/console/DependencyInjections/configuration/app.settings.json b/samples/dotnetcore/console/DependencyInjections/configuration/app.settings.json new file mode 100644 index 0000000..698d878 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/configuration/app.settings.json @@ -0,0 +1,3 @@ +{ + "StorageWrapper_ConnectionString": "UseDevelopmentStorage=true" +} diff --git a/samples/dotnetcore/console/DependencyInjections/configuration/samples.csproj b/samples/dotnetcore/console/DependencyInjections/configuration/samples.csproj new file mode 100644 index 0000000..869d4d2 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/configuration/samples.csproj @@ -0,0 +1,45 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + + + + + + + + + + Always + + + + + + + + + + + + + + + Always + + + diff --git a/samples/dotnetcore/console/DependencyInjections/configuration/samples.sln b/samples/dotnetcore/console/DependencyInjections/configuration/samples.sln new file mode 100644 index 0000000..e7b8f2a --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 d17.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{E4872347-A244-1216-9685-2A128BFF7897}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E535FAFC-112D-4859-B672-97650BE5D995} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/Program.cs b/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/Program.cs new file mode 100644 index 0000000..1ba3277 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/Program.cs @@ -0,0 +1,30 @@ +using AzureStorageWrapper; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using samples; + + +AzuriteHelper.Start();// Starts the Azurite process by executing the run-azurite.bat file + +var host = Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((context, config) => + { + config.AddJsonFile("app.settings.json", optional: false, reloadOnChange: true);// Add app.settings.json to the configuration + + }) + .ConfigureServices((context, services) => { + var connectionString = context.Configuration["StorageWrapper_ConnectionString"];// Get the StorageWrapper_ConnectionString string from the configuration + services.AddAzureStorageWrapper(connectionString);//Configuration AzureStorageWrapper + + services.AddExample_All();//Configuration Example_All + + }) + .Build(); + +var example_All = host.Services.GetService(); +await example_All.RunAsync();// Run the example_All service + +Console.WriteLine("Press any key to exit"); +Console.ReadKey(); + diff --git a/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/app.settings.json b/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/app.settings.json new file mode 100644 index 0000000..698d878 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/app.settings.json @@ -0,0 +1,3 @@ +{ + "StorageWrapper_ConnectionString": "UseDevelopmentStorage=true" +} diff --git a/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/samples.csproj b/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/samples.csproj new file mode 100644 index 0000000..869d4d2 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/samples.csproj @@ -0,0 +1,45 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + + + + + + + + + + Always + + + + + + + + + + + + + + + Always + + + diff --git a/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/samples.sln b/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/samples.sln new file mode 100644 index 0000000..2ec5072 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/connectionstring-configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 d17.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{E4872347-A244-1216-9685-2A128BFF7897}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D8263C58-8E2F-4657-9352-C360ABC107CC} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetcore/console/DependencyInjections/minimal-configuration/Program.cs b/samples/dotnetcore/console/DependencyInjections/minimal-configuration/Program.cs new file mode 100644 index 0000000..a81f61f --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/minimal-configuration/Program.cs @@ -0,0 +1,30 @@ +using AzureStorageWrapper; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using samples; + + +AzuriteHelper.Start();// Starts the Azurite process by executing the run-azurite.bat file + +var host = Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration((context, config) => + { + config.AddJsonFile("app.settings.json", optional: false, reloadOnChange: true);// Add app.settings.json to the configuration + + }) + .ConfigureServices((context, services) => { + Environment.SetEnvironmentVariable("StorageWrapper_ConnectionString", context.Configuration["StorageWrapper_ConnectionString"]);// Set the StorageWrapper_ConnectionString string in the environment variables + services.AddAzureStorageWrapper();//Configuration AzureStorageWrapper + + services.AddExample_All();//Configuration Example_All + + }) + .Build(); + +var example_All = host.Services.GetService(); +await example_All.RunAsync();// Run the example_All service + +Console.WriteLine("Press any key to exit"); +Console.ReadKey(); + diff --git a/samples/dotnetcore/console/DependencyInjections/minimal-configuration/app.settings.json b/samples/dotnetcore/console/DependencyInjections/minimal-configuration/app.settings.json new file mode 100644 index 0000000..698d878 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/minimal-configuration/app.settings.json @@ -0,0 +1,3 @@ +{ + "StorageWrapper_ConnectionString": "UseDevelopmentStorage=true" +} diff --git a/samples/dotnetcore/console/DependencyInjections/minimal-configuration/samples.csproj b/samples/dotnetcore/console/DependencyInjections/minimal-configuration/samples.csproj new file mode 100644 index 0000000..869d4d2 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/minimal-configuration/samples.csproj @@ -0,0 +1,45 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + + + + + + + + + + Always + + + + + + + + + + + + + + + Always + + + diff --git a/samples/dotnetcore/console/DependencyInjections/minimal-configuration/samples.sln b/samples/dotnetcore/console/DependencyInjections/minimal-configuration/samples.sln new file mode 100644 index 0000000..84fc3d3 --- /dev/null +++ b/samples/dotnetcore/console/DependencyInjections/minimal-configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 d17.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{E4872347-A244-1216-9685-2A128BFF7897}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {502EAC3D-7E74-4B8E-90A4-E84AEBD28312} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetcore/console/WithoutDependencyInjections/Program.cs b/samples/dotnetcore/console/WithoutDependencyInjections/Program.cs new file mode 100644 index 0000000..965dde3 --- /dev/null +++ b/samples/dotnetcore/console/WithoutDependencyInjections/Program.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Hosting; +using AzureStorageWrapper; +using samples; +using AzureStorageWrapper.Commands; +using samples.Helpers; + +AzuriteHelper.Start();// Starts the Azurite process by executing the run-azurite.bat file + +var host = Host.CreateDefaultBuilder(args) + .Build(); + +var options = new AzureStorageWrapperOptions +{ + ConnectionString = "UseDevelopmentStorage=true", + MaxSasUriExpiration=600, + DefaultSasUriExpiration = 300, + CreateContainerIfNotExists = true, +}; +var azureStorageWrapper = new AzureStorageWrapper.AzureStorageWrapper(options); + + +#region Upload Blobs In Bytes +ConsoleHelper.Start("Upload in Bytes"); +var bytes = Convert.FromBase64String("SGVsbG8g8J+Zgg=="); + +var command = new UploadBytes() +{ + Bytes = bytes, + Container = "files", + Name = "hello", + Extension = "md", + Metadata = new Dictionary() { { "key", "value" } } +}; + +var response = await azureStorageWrapper.UploadBlobAsync(command); +ConsoleHelper.Result(response); +ConsoleHelper.Finalized("Upload in Base64"); +#endregion + +Console.WriteLine("Press any key to exit"); +Console.ReadKey(); + diff --git a/samples/dotnetcore/console/WithoutDependencyInjections/samples.csproj b/samples/dotnetcore/console/WithoutDependencyInjections/samples.csproj new file mode 100644 index 0000000..6454214 --- /dev/null +++ b/samples/dotnetcore/console/WithoutDependencyInjections/samples.csproj @@ -0,0 +1,33 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + + + + + + Always + + + + + + + + + + + + diff --git a/samples/dotnetcore/console/WithoutDependencyInjections/samples.sln b/samples/dotnetcore/console/WithoutDependencyInjections/samples.sln new file mode 100644 index 0000000..7bf7d40 --- /dev/null +++ b/samples/dotnetcore/console/WithoutDependencyInjections/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 d17.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{E4872347-A244-1216-9685-2A128BFF7897}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{B73B6239-54A0-7B08-257C-59BFD8269DD3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E4872347-A244-1216-9685-2A128BFF7897}.Release|Any CPU.Build.0 = Release|Any CPU + {B73B6239-54A0-7B08-257C-59BFD8269DD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B73B6239-54A0-7B08-257C-59BFD8269DD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B73B6239-54A0-7B08-257C-59BFD8269DD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B73B6239-54A0-7B08-257C-59BFD8269DD3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C0D22797-57A6-4A81-9FA8-B29742B8D3BB} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetfw/console/DependencyInjections/configuration/App.config b/samples/dotnetfw/console/DependencyInjections/configuration/App.config new file mode 100644 index 0000000..cb31273 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/configuration/App.config @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/dotnetfw/console/DependencyInjections/configuration/Program.cs b/samples/dotnetfw/console/DependencyInjections/configuration/Program.cs new file mode 100644 index 0000000..4f3a7de --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/configuration/Program.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Specialized; +using System.Configuration; +using System.Threading.Tasks; +using AzureStorageWrapper; +using Microsoft.Extensions.DependencyInjection; + +namespace samples +{ + class Program + { + static async Task Main(string[] args) + { + AzuriteHelper.Start();// Starts the Azurite process by executing the run-azurite.bat file + var serviceProvider = ConfigureServices((configuration, services) => + { + var connectionString = configuration["StorageWrapper_ConnectionString"];// Set the StorageWrapper_ConnectionString string in the environment variables + services.AddAzureStorageWrapper(options => + { + options.ConnectionString = connectionString; + options.MaxSasUriExpiration = 600; + options.DefaultSasUriExpiration = 300; + options.CreateContainerIfNotExists = true; + });//Configuration AzureStorageWrapper + + services.AddExample_All();//Configuration Example_All + + }); + + var example_All = serviceProvider.GetService(); + await example_All.RunAsync();// Run the example_All service + + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + + private static ServiceProvider ConfigureServices(Action configurateDelegate) + { + var services = new ServiceCollection(); + configurateDelegate(ConfigurationManager.AppSettings, services); + // Construir el proveedor de servicios + return services.BuildServiceProvider(); + } + } +} diff --git a/samples/dotnetfw/console/DependencyInjections/configuration/Properties/AssemblyInfo.cs b/samples/dotnetfw/console/DependencyInjections/configuration/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..005d673 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/configuration/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("samples")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("samples")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0168626a-763d-4d49-8fda-59f540d56f9d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/dotnetfw/console/DependencyInjections/configuration/packages.config b/samples/dotnetfw/console/DependencyInjections/configuration/packages.config new file mode 100644 index 0000000..42ebfb2 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/configuration/packages.config @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/dotnetfw/console/DependencyInjections/configuration/samples.csproj b/samples/dotnetfw/console/DependencyInjections/configuration/samples.csproj new file mode 100644 index 0000000..e0d5809 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/configuration/samples.csproj @@ -0,0 +1,211 @@ + + + + + Debug + AnyCPU + {0168626A-763D-4D49-8FDA-59F540D56F9D} + Exe + samples + samples + v4.6.2 + 10.0 + 512 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + $(DefineConstants);NETFRAMEWORK + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + $(DefineConstants);NETFRAMEWORK + + + + packages\Azure.Core.1.44.1\lib\net461\Azure.Core.dll + + + packages\Azure.Storage.Blobs.12.23.0\lib\netstandard2.0\Azure.Storage.Blobs.dll + + + packages\Azure.Storage.Common.12.22.0\lib\netstandard2.0\Azure.Storage.Common.dll + + + packages\Ensure.That.10.1.0\lib\net451\Ensure.That.dll + + + packages\Microsoft.Bcl.AsyncInterfaces.9.0.2\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + packages\Microsoft.Bcl.Cryptography.9.0.2\lib\net462\Microsoft.Bcl.Cryptography.dll + + + packages\Microsoft.Extensions.DependencyInjection.9.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.dll + + + packages\Microsoft.Extensions.DependencyInjection.Abstractions.9.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + packages\Microsoft.Extensions.FileProviders.Abstractions.9.0.2\lib\net462\Microsoft.Extensions.FileProviders.Abstractions.dll + + + packages\Microsoft.Extensions.FileProviders.Physical.9.0.2\lib\net462\Microsoft.Extensions.FileProviders.Physical.dll + + + packages\Microsoft.Extensions.FileSystemGlobbing.9.0.2\lib\net462\Microsoft.Extensions.FileSystemGlobbing.dll + + + packages\Microsoft.Extensions.Primitives.9.0.2\lib\net462\Microsoft.Extensions.Primitives.dll + + + packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + packages\System.ClientModel.1.1.0\lib\netstandard2.0\System.ClientModel.dll + + + + + packages\System.Diagnostics.DiagnosticSource.6.0.1\lib\net461\System.Diagnostics.DiagnosticSource.dll + + + packages\System.Formats.Asn1.9.0.2\lib\net462\System.Formats.Asn1.dll + + + packages\System.IO.Hashing.6.0.0\lib\net461\System.IO.Hashing.dll + + + packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + packages\System.Memory.Data.6.0.0\lib\net461\System.Memory.Data.dll + + + packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True + True + + + + packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + + packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + + packages\System.Security.Cryptography.Xml.9.0.2\lib\net462\System.Security.Cryptography.Xml.dll + + + packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll + + + packages\System.Text.Json.6.0.10\lib\net461\System.Text.Json.dll + + + packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + + + + + + + + + + AzuriteHelper.cs + + + ConsoleHelper.cs + + + Delete_Blobs.cs + + + Download_Blobs.cs + + + Enumerate_Blobs.cs + + + Samples_All.cs + + + Upload_Blobs.cs + + + Virtual_Folders.cs + + + + + + + run-azurite.bat + Always + + + run-azurite.sh + Always + + + Always + + + + + + {ea9579ca-1424-4e11-53e8-3b6515ff217f} + AzureStorageWrapper + + + + \ No newline at end of file diff --git a/samples/dotnetfw/console/DependencyInjections/configuration/samples.sln b/samples/dotnetfw/console/DependencyInjections/configuration/samples.sln new file mode 100644 index 0000000..76b59c8 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{0168626A-763D-4D49-8FDA-59F540D56F9D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AF4E9CB7-62C0-4DE5-8A07-D8FF9BD9DF45} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/App.config b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/App.config new file mode 100644 index 0000000..cb31273 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/App.config @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/Program.cs b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/Program.cs new file mode 100644 index 0000000..91c2f8b --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/Program.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Specialized; +using System.Configuration; +using System.Threading.Tasks; +using AzureStorageWrapper; +using Microsoft.Extensions.DependencyInjection; + +namespace samples +{ + class Program + { + static async Task Main(string[] args) + { + AzuriteHelper.Start();// Starts the Azurite process by executing the run-azurite.bat file + var serviceProvider = ConfigureServices((configuration, services) => + { + var connectionString = configuration["StorageWrapper_ConnectionString"];// Set the StorageWrapper_ConnectionString string in the environment variables + services.AddAzureStorageWrapper(connectionString);//Configuration AzureStorageWrapper + + services.AddExample_All();//Configuration Example_All + + }); + + var example_All = serviceProvider.GetService(); + await example_All.RunAsync();// Run the example_All service + + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + + private static ServiceProvider ConfigureServices(Action configurateDelegate) + { + var services = new ServiceCollection(); + configurateDelegate(ConfigurationManager.AppSettings, services); + // Construir el proveedor de servicios + return services.BuildServiceProvider(); + } + } +} diff --git a/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/Properties/AssemblyInfo.cs b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..005d673 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("samples")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("samples")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0168626a-763d-4d49-8fda-59f540d56f9d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/packages.config b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/packages.config new file mode 100644 index 0000000..42ebfb2 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/packages.config @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/samples.csproj b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/samples.csproj new file mode 100644 index 0000000..e0d5809 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/samples.csproj @@ -0,0 +1,211 @@ + + + + + Debug + AnyCPU + {0168626A-763D-4D49-8FDA-59F540D56F9D} + Exe + samples + samples + v4.6.2 + 10.0 + 512 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + $(DefineConstants);NETFRAMEWORK + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + $(DefineConstants);NETFRAMEWORK + + + + packages\Azure.Core.1.44.1\lib\net461\Azure.Core.dll + + + packages\Azure.Storage.Blobs.12.23.0\lib\netstandard2.0\Azure.Storage.Blobs.dll + + + packages\Azure.Storage.Common.12.22.0\lib\netstandard2.0\Azure.Storage.Common.dll + + + packages\Ensure.That.10.1.0\lib\net451\Ensure.That.dll + + + packages\Microsoft.Bcl.AsyncInterfaces.9.0.2\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + packages\Microsoft.Bcl.Cryptography.9.0.2\lib\net462\Microsoft.Bcl.Cryptography.dll + + + packages\Microsoft.Extensions.DependencyInjection.9.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.dll + + + packages\Microsoft.Extensions.DependencyInjection.Abstractions.9.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + packages\Microsoft.Extensions.FileProviders.Abstractions.9.0.2\lib\net462\Microsoft.Extensions.FileProviders.Abstractions.dll + + + packages\Microsoft.Extensions.FileProviders.Physical.9.0.2\lib\net462\Microsoft.Extensions.FileProviders.Physical.dll + + + packages\Microsoft.Extensions.FileSystemGlobbing.9.0.2\lib\net462\Microsoft.Extensions.FileSystemGlobbing.dll + + + packages\Microsoft.Extensions.Primitives.9.0.2\lib\net462\Microsoft.Extensions.Primitives.dll + + + packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + packages\System.ClientModel.1.1.0\lib\netstandard2.0\System.ClientModel.dll + + + + + packages\System.Diagnostics.DiagnosticSource.6.0.1\lib\net461\System.Diagnostics.DiagnosticSource.dll + + + packages\System.Formats.Asn1.9.0.2\lib\net462\System.Formats.Asn1.dll + + + packages\System.IO.Hashing.6.0.0\lib\net461\System.IO.Hashing.dll + + + packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + packages\System.Memory.Data.6.0.0\lib\net461\System.Memory.Data.dll + + + packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True + True + + + + packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + + packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + + packages\System.Security.Cryptography.Xml.9.0.2\lib\net462\System.Security.Cryptography.Xml.dll + + + packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll + + + packages\System.Text.Json.6.0.10\lib\net461\System.Text.Json.dll + + + packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + + + + + + + + + + AzuriteHelper.cs + + + ConsoleHelper.cs + + + Delete_Blobs.cs + + + Download_Blobs.cs + + + Enumerate_Blobs.cs + + + Samples_All.cs + + + Upload_Blobs.cs + + + Virtual_Folders.cs + + + + + + + run-azurite.bat + Always + + + run-azurite.sh + Always + + + Always + + + + + + {ea9579ca-1424-4e11-53e8-3b6515ff217f} + AzureStorageWrapper + + + + \ No newline at end of file diff --git a/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/samples.sln b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/samples.sln new file mode 100644 index 0000000..76b59c8 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/connectionstring-configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{0168626A-763D-4D49-8FDA-59F540D56F9D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AF4E9CB7-62C0-4DE5-8A07-D8FF9BD9DF45} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetfw/console/DependencyInjections/minimal-configuration/App.config b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/App.config new file mode 100644 index 0000000..cb31273 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/App.config @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/dotnetfw/console/DependencyInjections/minimal-configuration/Program.cs b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/Program.cs new file mode 100644 index 0000000..36c9682 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/Program.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Specialized; +using System.Configuration; +using System.Threading.Tasks; +using AzureStorageWrapper; +using Microsoft.Extensions.DependencyInjection; + +namespace samples +{ + class Program + { + static async Task Main(string[] args) + { + AzuriteHelper.Start();// Starts the Azurite process by executing the run-azurite.bat file + var serviceProvider = ConfigureServices((configuration, services) => + { + Environment.SetEnvironmentVariable("StorageWrapper_ConnectionString", configuration["StorageWrapper_ConnectionString"]);// Set the StorageWrapper_ConnectionString string in the environment variables + services.AddAzureStorageWrapper();//Configuration AzureStorageWrapper + + services.AddExample_All();//Configuration Example_All + + }); + + var example_All = serviceProvider.GetService(); + await example_All.RunAsync();// Run the example_All service + + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + + private static ServiceProvider ConfigureServices(Action configurateDelegate) + { + var services = new ServiceCollection(); + configurateDelegate(ConfigurationManager.AppSettings, services); + // Construir el proveedor de servicios + return services.BuildServiceProvider(); + } + } +} diff --git a/samples/dotnetfw/console/DependencyInjections/minimal-configuration/Properties/AssemblyInfo.cs b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..005d673 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("samples")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("samples")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0168626a-763d-4d49-8fda-59f540d56f9d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/dotnetfw/console/DependencyInjections/minimal-configuration/packages.config b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/packages.config new file mode 100644 index 0000000..42ebfb2 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/packages.config @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/dotnetfw/console/DependencyInjections/minimal-configuration/samples.csproj b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/samples.csproj new file mode 100644 index 0000000..e0d5809 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/samples.csproj @@ -0,0 +1,211 @@ + + + + + Debug + AnyCPU + {0168626A-763D-4D49-8FDA-59F540D56F9D} + Exe + samples + samples + v4.6.2 + 10.0 + 512 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + $(DefineConstants);NETFRAMEWORK + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + $(DefineConstants);NETFRAMEWORK + + + + packages\Azure.Core.1.44.1\lib\net461\Azure.Core.dll + + + packages\Azure.Storage.Blobs.12.23.0\lib\netstandard2.0\Azure.Storage.Blobs.dll + + + packages\Azure.Storage.Common.12.22.0\lib\netstandard2.0\Azure.Storage.Common.dll + + + packages\Ensure.That.10.1.0\lib\net451\Ensure.That.dll + + + packages\Microsoft.Bcl.AsyncInterfaces.9.0.2\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + packages\Microsoft.Bcl.Cryptography.9.0.2\lib\net462\Microsoft.Bcl.Cryptography.dll + + + packages\Microsoft.Extensions.DependencyInjection.9.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.dll + + + packages\Microsoft.Extensions.DependencyInjection.Abstractions.9.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + packages\Microsoft.Extensions.FileProviders.Abstractions.9.0.2\lib\net462\Microsoft.Extensions.FileProviders.Abstractions.dll + + + packages\Microsoft.Extensions.FileProviders.Physical.9.0.2\lib\net462\Microsoft.Extensions.FileProviders.Physical.dll + + + packages\Microsoft.Extensions.FileSystemGlobbing.9.0.2\lib\net462\Microsoft.Extensions.FileSystemGlobbing.dll + + + packages\Microsoft.Extensions.Primitives.9.0.2\lib\net462\Microsoft.Extensions.Primitives.dll + + + packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + packages\System.ClientModel.1.1.0\lib\netstandard2.0\System.ClientModel.dll + + + + + packages\System.Diagnostics.DiagnosticSource.6.0.1\lib\net461\System.Diagnostics.DiagnosticSource.dll + + + packages\System.Formats.Asn1.9.0.2\lib\net462\System.Formats.Asn1.dll + + + packages\System.IO.Hashing.6.0.0\lib\net461\System.IO.Hashing.dll + + + packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + packages\System.Memory.Data.6.0.0\lib\net461\System.Memory.Data.dll + + + packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True + True + + + + packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + + packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + + packages\System.Security.Cryptography.Xml.9.0.2\lib\net462\System.Security.Cryptography.Xml.dll + + + packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll + + + packages\System.Text.Json.6.0.10\lib\net461\System.Text.Json.dll + + + packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + + + + + + + + + + AzuriteHelper.cs + + + ConsoleHelper.cs + + + Delete_Blobs.cs + + + Download_Blobs.cs + + + Enumerate_Blobs.cs + + + Samples_All.cs + + + Upload_Blobs.cs + + + Virtual_Folders.cs + + + + + + + run-azurite.bat + Always + + + run-azurite.sh + Always + + + Always + + + + + + {ea9579ca-1424-4e11-53e8-3b6515ff217f} + AzureStorageWrapper + + + + \ No newline at end of file diff --git a/samples/dotnetfw/console/DependencyInjections/minimal-configuration/samples.sln b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/samples.sln new file mode 100644 index 0000000..76b59c8 --- /dev/null +++ b/samples/dotnetfw/console/DependencyInjections/minimal-configuration/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{0168626A-763D-4D49-8FDA-59F540D56F9D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AF4E9CB7-62C0-4DE5-8A07-D8FF9BD9DF45} + EndGlobalSection +EndGlobal diff --git a/samples/dotnetfw/console/WithoutDependencyInjections/App.config b/samples/dotnetfw/console/WithoutDependencyInjections/App.config new file mode 100644 index 0000000..61cbe8c --- /dev/null +++ b/samples/dotnetfw/console/WithoutDependencyInjections/App.config @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/dotnetfw/console/WithoutDependencyInjections/Program.cs b/samples/dotnetfw/console/WithoutDependencyInjections/Program.cs new file mode 100644 index 0000000..14d6d58 --- /dev/null +++ b/samples/dotnetfw/console/WithoutDependencyInjections/Program.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using AzureStorageWrapper; +using AzureStorageWrapper.Commands; +using samples.Helpers; + +namespace samples +{ + class Program + { + static async Task Main(string[] args) + { + AzuriteHelper.Start();// Starts the Azurite process by executing the run-azurite.bat file + var options = new AzureStorageWrapperOptions + { + ConnectionString = "UseDevelopmentStorage=true", + MaxSasUriExpiration = 600, + DefaultSasUriExpiration = 300, + CreateContainerIfNotExists = true, + }; + var azureStorageWrapper = new AzureStorageWrapper.AzureStorageWrapper(options); + + + #region Upload Blobs In Bytes + ConsoleHelper.Start("Upload in Bytes"); + var bytes = Convert.FromBase64String("SGVsbG8g8J+Zgg=="); + + var command = new UploadBytes() + { + Bytes = bytes, + Container = "files", + Name = "hello", + Extension = "md", + Metadata = new Dictionary() { { "key", "value" } } + }; + + var response = await azureStorageWrapper.UploadBlobAsync(command); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Upload in Base64"); + #endregion + + Console.WriteLine("Press any key to exit"); + Console.ReadKey(); + } + } +} diff --git a/samples/dotnetfw/console/WithoutDependencyInjections/Properties/AssemblyInfo.cs b/samples/dotnetfw/console/WithoutDependencyInjections/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..005d673 --- /dev/null +++ b/samples/dotnetfw/console/WithoutDependencyInjections/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("samples")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("samples")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0168626a-763d-4d49-8fda-59f540d56f9d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/dotnetfw/console/WithoutDependencyInjections/packages.config b/samples/dotnetfw/console/WithoutDependencyInjections/packages.config new file mode 100644 index 0000000..42ebfb2 --- /dev/null +++ b/samples/dotnetfw/console/WithoutDependencyInjections/packages.config @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/dotnetfw/console/WithoutDependencyInjections/samples.csproj b/samples/dotnetfw/console/WithoutDependencyInjections/samples.csproj new file mode 100644 index 0000000..3749c2e --- /dev/null +++ b/samples/dotnetfw/console/WithoutDependencyInjections/samples.csproj @@ -0,0 +1,211 @@ + + + + + Debug + AnyCPU + {0168626A-763D-4D49-8FDA-59F540D56F9D} + Exe + samples + samples + v4.6.2 + 10.0 + 512 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + $(DefineConstants);NETFRAMEWORK + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + $(DefineConstants);NETFRAMEWORK + + + + packages\Azure.Core.1.44.1\lib\net461\Azure.Core.dll + + + packages\Azure.Storage.Blobs.12.23.0\lib\netstandard2.0\Azure.Storage.Blobs.dll + + + packages\Azure.Storage.Common.12.22.0\lib\netstandard2.0\Azure.Storage.Common.dll + + + packages\Ensure.That.10.1.0\lib\net451\Ensure.That.dll + + + packages\Microsoft.Bcl.AsyncInterfaces.9.0.2\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + packages\Microsoft.Bcl.Cryptography.9.0.2\lib\net462\Microsoft.Bcl.Cryptography.dll + + + packages\Microsoft.Extensions.DependencyInjection.9.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.dll + + + packages\Microsoft.Extensions.DependencyInjection.Abstractions.9.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + packages\Microsoft.Extensions.FileProviders.Abstractions.9.0.2\lib\net462\Microsoft.Extensions.FileProviders.Abstractions.dll + + + packages\Microsoft.Extensions.FileProviders.Physical.9.0.2\lib\net462\Microsoft.Extensions.FileProviders.Physical.dll + + + packages\Microsoft.Extensions.FileSystemGlobbing.9.0.2\lib\net462\Microsoft.Extensions.FileSystemGlobbing.dll + + + packages\Microsoft.Extensions.Primitives.9.0.2\lib\net462\Microsoft.Extensions.Primitives.dll + + + packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + packages\System.ClientModel.1.1.0\lib\netstandard2.0\System.ClientModel.dll + + + + + packages\System.Diagnostics.DiagnosticSource.6.0.1\lib\net461\System.Diagnostics.DiagnosticSource.dll + + + packages\System.Formats.Asn1.9.0.2\lib\net462\System.Formats.Asn1.dll + + + packages\System.IO.Hashing.6.0.0\lib\net461\System.IO.Hashing.dll + + + packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + packages\System.Memory.Data.6.0.0\lib\net461\System.Memory.Data.dll + + + packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True + True + + + + packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + True + + + + packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll + True + True + + + packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + True + + + packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + True + + + packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + True + + + packages\System.Security.Cryptography.Xml.9.0.2\lib\net462\System.Security.Cryptography.Xml.dll + + + packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll + + + packages\System.Text.Json.6.0.10\lib\net461\System.Text.Json.dll + + + packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll + + + + + + + + + + AzuriteHelper.cs + + + ConsoleHelper.cs + + + Delete_Blobs.cs + + + Download_Blobs.cs + + + Enumerate_Blobs.cs + + + Samples_All.cs + + + Upload_Blobs.cs + + + Virtual_Folders.cs + + + + + + + run-azurite.bat + Always + + + run-azurite.sh + Always + + + Always + + + + + + {ea9579ca-1424-4e11-53e8-3b6515ff217f} + AzureStorageWrapper + + + + \ No newline at end of file diff --git a/samples/dotnetfw/console/WithoutDependencyInjections/samples.sln b/samples/dotnetfw/console/WithoutDependencyInjections/samples.sln new file mode 100644 index 0000000..5e1c6b2 --- /dev/null +++ b/samples/dotnetfw/console/WithoutDependencyInjections/samples.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35825.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "samples", "samples.csproj", "{0168626A-763D-4D49-8FDA-59F540D56F9D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureStorageWrapper", "..\..\..\..\src\AzureStorageWrapper\AzureStorageWrapper.csproj", "{EA9579CA-1424-4E11-53E8-3B6515FF217F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0168626A-763D-4D49-8FDA-59F540D56F9D}.Release|Any CPU.Build.0 = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA9579CA-1424-4E11-53E8-3B6515FF217F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AF4E9CB7-62C0-4DE5-8A07-D8FF9BD9DF45} + EndGlobalSection +EndGlobal diff --git a/samples/sharedcontent/AzuriteHelper.cs b/samples/sharedcontent/AzuriteHelper.cs new file mode 100644 index 0000000..2259fcc --- /dev/null +++ b/samples/sharedcontent/AzuriteHelper.cs @@ -0,0 +1,18 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Threading; + +namespace samples; + +public static class AzuriteHelper +{ + public static void Start() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + Process.Start($"{Environment.CurrentDirectory}\\run-azurite.bat"); + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + Process.Start($"{Environment.CurrentDirectory}\\run-azurite.sh"); + Thread.Sleep(4000); + } +} diff --git a/samples/sharedcontent/ConsoleHelper.cs b/samples/sharedcontent/ConsoleHelper.cs new file mode 100644 index 0000000..cf008f6 --- /dev/null +++ b/samples/sharedcontent/ConsoleHelper.cs @@ -0,0 +1,55 @@ +using System; +using System.Security.Cryptography; +using Newtonsoft.Json; + +#if NETCOREAPP +using System.Text.Json; +#elif NETFRAMEWORK + +#endif + +namespace samples.Helpers +{ + public static class ConsoleHelper + { + private const ConsoleColor _blockColor = ConsoleColor.Cyan; + private const ConsoleColor _resultColor = ConsoleColor.Green; + private const ConsoleColor _moduleColor = ConsoleColor.Yellow; + private const ConsoleColor _infoColor = ConsoleColor.White; + +#if NET + private static JsonSerializerOptions _jsonSerializerOptions => new JsonSerializerOptions() { WriteIndented = true }; +#elif NETFRAMEWORK + private static JsonSerializerSettings _jsonSerializerSettings => new JsonSerializerSettings { Formatting = Formatting.Indented }; +#endif + + public static void Info(string message) => WriteImpl(message, _infoColor); + public static void Module(string message) => WriteImpl($"\r\n{message}\r\n", _moduleColor); + + public static void Start(string message) => WriteImpl($"\r\n=== {message} ===", _blockColor); + public static void Finalized(string message) => WriteImpl($"=== FIN - {message} ===", _blockColor); + + public static void Result(object value) + { +#if NET + var message = $"Result: {JsonSerializer.Serialize(value, _jsonSerializerOptions)}"; +#elif NETFRAMEWORK + var message = $"Result: {JsonConvert.SerializeObject(value, _jsonSerializerSettings)}"; +#endif + Result(message); + } + public static void Result(string message) => WriteImpl(message, _resultColor); + + + + private static void WriteImpl(string message, ConsoleColor color, bool isLine = true) + { + Console.ForegroundColor = color; + if (isLine) + Console.WriteLine(message); + else + Console.Write(message); + Console.ResetColor(); + } + } +} diff --git a/samples/sharedcontent/Delete_Blobs.cs b/samples/sharedcontent/Delete_Blobs.cs new file mode 100644 index 0000000..42a37b6 --- /dev/null +++ b/samples/sharedcontent/Delete_Blobs.cs @@ -0,0 +1,31 @@ +using System.Threading.Tasks; +using AzureStorageWrapper; +using AzureStorageWrapper.Commands; +using samples.Helpers; + +namespace samples +{ + public class Delete_Blobs + { + readonly IAzureStorageWrapper _azureStorageWrapper; + public Delete_Blobs(IAzureStorageWrapper azureStorageWrapper) + { + _azureStorageWrapper = azureStorageWrapper; + } + public async Task RunAllAsync() + { + ConsoleHelper.Module("**** DELETE BLOBS ****"); + } + public async Task DeleteAsync() + { + ConsoleHelper.Start("Delete Blobs"); + var command = new DeleteBlob() + { + Uri = "https://accountName.blob.core.windows.net/files/5a19306fc5014a4/hello.md" + }; + + await _azureStorageWrapper.DeleteBlobAsync(command); ConsoleHelper.Finalized("Download in Base64"); + ConsoleHelper.Finalized("Delete Blobs"); + } + } +} diff --git a/samples/sharedcontent/Download_Blobs.cs b/samples/sharedcontent/Download_Blobs.cs new file mode 100644 index 0000000..c86d90d --- /dev/null +++ b/samples/sharedcontent/Download_Blobs.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AzureStorageWrapper; +using AzureStorageWrapper.Commands; +using AzureStorageWrapper.Queries; +using AzureStorageWrapper.Responses; +using samples.Helpers; + +namespace samples +{ + public class Download_Blobs + { + readonly IAzureStorageWrapper _azureStorageWrapper; + public Download_Blobs(IAzureStorageWrapper azureStorageWrapper) + { + _azureStorageWrapper = azureStorageWrapper; + } + public async Task RunAllAsync() + { + ConsoleHelper.Module("**** DOWNLOAD BLOBS ****"); + await DownloadBlobReferencesAsync(); + } + + public async Task DownloadBlobReferencesAsync() + { + var uri = await UploadFileAsynt(); + ConsoleHelper.Start("Download Blob References"); + var query = new DownloadBlobReference() + { + Uri = uri, + ExpiresIn = 60 + }; + + var response = await _azureStorageWrapper.DownloadBlobReferenceAsync(query); ConsoleHelper.Result(response); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Download Blob References"); + } + + + private async Task UploadFileAsynt() + { + var base64 = "SGVsbG8g8J+Zgg=="; + + var uploadBlobCommand = new UploadBase64() + { + Base64 = base64, + Container = "files", + Name = "hello", + Extension = "md", + Metadata = new Dictionary() + {{"hello", "world"}} + }; + + var response = await _azureStorageWrapper.UploadBlobAsync(uploadBlobCommand); + return response.Uri; + } + } +} diff --git a/samples/sharedcontent/Enumerate_Blobs.cs b/samples/sharedcontent/Enumerate_Blobs.cs new file mode 100644 index 0000000..09c8e05 --- /dev/null +++ b/samples/sharedcontent/Enumerate_Blobs.cs @@ -0,0 +1,78 @@ +using System.Threading.Tasks; +using AzureStorageWrapper; +using AzureStorageWrapper.Queries; +using samples.Helpers; + +namespace samples +{ + public class Enumerate_Blobs + { + readonly IAzureStorageWrapper _azureStorageWrapper; + public Enumerate_Blobs(IAzureStorageWrapper azureStorageWrapper) + { + _azureStorageWrapper = azureStorageWrapper; + } + public async Task RunAllAsync() + { + ConsoleHelper.Module("**** ENUMERATE BLOBS ****"); + await EnumerateWithoutPaginationAsync(); + await EnumerateWithPaginationWithoutContinationTokenAsync(); + await EnumerateWithPaginationWithContinationTokenAsync(); + } + + public async Task EnumerateWithoutPaginationAsync() + { + ConsoleHelper.Start("Enumerate Blobs without Pagination"); + var query = new EnumerateBlobs() + { + Container = "files", + Paginate = false + }; + + var response = await _azureStorageWrapper.EnumerateBlobsAsync(query); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Enumerate Blobs without Pagination"); + } + + public async Task EnumerateWithPaginationWithoutContinationTokenAsync() + { + ConsoleHelper.Start("Enumerate Blobs with Pagination and without ContinationToken"); + var query = new EnumerateBlobs() + { + Container = "files", + Paginate = true, + Size = 10, + }; + + var response = await _azureStorageWrapper.EnumerateBlobsAsync(query); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Enumerate Blobs with Pagination and without ContinationToken"); + } + + public async Task EnumerateWithPaginationWithContinationTokenAsync() + { + ConsoleHelper.Start("Enumerate Blobs with Pagination and with ContinationToken"); + var firstQuery = new EnumerateBlobs() + { + Container = "files", + Paginate = true, + Size = 10, + }; + + var firstResponse = await _azureStorageWrapper.EnumerateBlobsAsync(firstQuery); + ConsoleHelper.Result(firstResponse); + + var secondQuery = new EnumerateBlobs() + { + Container = "files", + Paginate = true, + Size = 10, + ContinuationToken = firstResponse.ContinuationToken + }; + + var secondResponse = await _azureStorageWrapper.EnumerateBlobsAsync(secondQuery); + ConsoleHelper.Result(secondResponse); + ConsoleHelper.Finalized("Enumerate Blobs with Pagination and with ContinationToken"); + } + } +} diff --git a/samples/sharedcontent/Samples_All.cs b/samples/sharedcontent/Samples_All.cs new file mode 100644 index 0000000..36dfc2e --- /dev/null +++ b/samples/sharedcontent/Samples_All.cs @@ -0,0 +1,52 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using samples.Helpers; + +namespace samples +{ + public class Samples_All + { + private readonly Upload_Blobs _upload_Blobs; + private readonly Virtual_Folders _virtual_Folders; + private readonly Delete_Blobs _delete_Blobs; + private readonly Download_Blobs _download_Blobs; + private readonly Enumerate_Blobs _enumerate_Blobs; + public Samples_All(Upload_Blobs upload_Blobs, Virtual_Folders virtual_Folders,Delete_Blobs delete_Blobs, + Download_Blobs download_Blobs, Enumerate_Blobs enumerate_Blobs) + { + _upload_Blobs = upload_Blobs; + _virtual_Folders = virtual_Folders; + _delete_Blobs = delete_Blobs; + _download_Blobs = download_Blobs; + _enumerate_Blobs = enumerate_Blobs; + } + + public async Task RunAsync() + { + ConsoleHelper.Info("Samples - All"); + await _upload_Blobs.RunAllAsync(); + await _virtual_Folders.RunAllAsync(); + await _download_Blobs.RunAllAsync(); + await _delete_Blobs.RunAllAsync(); + await _enumerate_Blobs.RunAllAsync(); + ConsoleHelper.Info(""); + ConsoleHelper.Info("FIN - Samples - All"); + } + } + + public static class Example_All_DependencyInjection + { + public static IServiceCollection AddExample_All(this IServiceCollection services) + { + services.AddScoped() + .AddScoped() + .AddScoped() + .AddScoped() + .AddScoped() + .AddScoped() + ; + return services; + } + } + +} diff --git a/samples/sharedcontent/Upload_Blobs.cs b/samples/sharedcontent/Upload_Blobs.cs new file mode 100644 index 0000000..38e84ab --- /dev/null +++ b/samples/sharedcontent/Upload_Blobs.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using AzureStorageWrapper; +using AzureStorageWrapper.Commands; +using samples.Helpers; + +namespace samples +{ + public class Upload_Blobs + { + readonly IAzureStorageWrapper _azureStorageWrapper; + public Upload_Blobs(IAzureStorageWrapper azureStorageWrapper) + { + _azureStorageWrapper = azureStorageWrapper; + } + + public async Task RunAllAsync() + { + ConsoleHelper.Module("**** UPLOAD BLOBS ****"); + await UploadInBase64Async(); + await UploadInBytesAsync(); + await UploadInStreamAsync(); + } + + public async Task UploadInBase64Async() + { + ConsoleHelper.Start("Upload in Base64"); + var base64 = "SGVsbG8g8J+Zgg=="; + + var command = new UploadBase64() + { + Base64 = base64, + Container = "files", + Name = "hello", + Extension = "md", + Metadata = new Dictionary() { { "key", "value" } } + }; + + var response = await _azureStorageWrapper.UploadBlobAsync(command); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Upload in Base64"); + } + + public async Task UploadInBytesAsync() + { + ConsoleHelper.Start("Upload in Bytes"); + var bytes = Convert.FromBase64String("SGVsbG8g8J+Zgg=="); + + var command = new UploadBytes() + { + Bytes = bytes, + Container = "files", + Name = "hello", + Extension = "md", + Metadata = new Dictionary() { { "key", "value" } } + }; + + var response = await _azureStorageWrapper.UploadBlobAsync(command); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Upload in Base64"); + } + + public async Task UploadInStreamAsync() + { + ConsoleHelper.Start("Upload in Bytes"); + var stream = new MemoryStream(Convert.FromBase64String("SGVsbG8g8J+Zgg==")); + + var command = new UploadStream() + { + Stream = stream, + Container = "files", + Name = "hello", + Extension = "md", + Metadata = new Dictionary() { { "key", "value" } } + }; + + var response = await _azureStorageWrapper.UploadBlobAsync(command); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Upload in Base64"); + } + } +} diff --git a/samples/sharedcontent/Virtual_Folders.cs b/samples/sharedcontent/Virtual_Folders.cs new file mode 100644 index 0000000..7e0d942 --- /dev/null +++ b/samples/sharedcontent/Virtual_Folders.cs @@ -0,0 +1,62 @@ +using System; +using System.Threading.Tasks; +using AzureStorageWrapper; +using AzureStorageWrapper.Commands; +using samples.Helpers; + +namespace samples +{ + public class Virtual_Folders + { + readonly IAzureStorageWrapper _azureStorageWrapper; + public Virtual_Folders(IAzureStorageWrapper azureStorageWrapper) + { + _azureStorageWrapper = azureStorageWrapper; + } + + public async Task RunAllAsync() + { + ConsoleHelper.Module("**** VIRTUAL FOLDERS ****"); + await UploadWithVirtualFolderASync(); + await UploadWithoutVirtualFolderASync(); + } + + public async Task UploadWithVirtualFolderASync() + { + ConsoleHelper.Start("Upload With Virtual Folders"); + var base64 = "SGVsbG8g8J+Zgg=="; + + var command = new UploadBase64() + { + Base64 = base64, + Container = "files", + Name = $"{Guid.NewGuid()}", + Extension = "md", + UseVirtualFolder = true// Default: True; + }; + + var response = await _azureStorageWrapper.UploadBlobAsync(command); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Upload With Virtual Folders"); + } + public async Task UploadWithoutVirtualFolderASync() + { + ConsoleHelper.Start("Upload Without Virtual Folders"); + var base64 = "SGVsbG8g8J+Zgg=="; + + var command = new UploadBase64() + { + Base64 = base64, + Container = "files", + Name = $"{Guid.NewGuid()}", + Extension = "md", + UseVirtualFolder = false + }; + + var response = await _azureStorageWrapper.UploadBlobAsync(command); + ConsoleHelper.Result(response); + ConsoleHelper.Finalized("Upload Without Virtual Folders"); + } + + } +} diff --git a/samples/sharedcontent/run-azurite.bat b/samples/sharedcontent/run-azurite.bat new file mode 100644 index 0000000..f162d48 --- /dev/null +++ b/samples/sharedcontent/run-azurite.bat @@ -0,0 +1,11 @@ +@echo off + +REM Instructions to run this script: +REM 1. Make sure you have Azurite installed. You can install it using npm: +REM npm install -g azurite +REM 2. Make sure you have the .NET SDK installed and the `dotnet` command available in your PATH. +REM 3. Run the script by double-clicking it or executing it from the command line. + +echo Starting Azurite... +start /B azurite -s -l c:\azurite -d c:\azurite\debug.log +pause diff --git a/samples/sharedcontent/run-azurite.sh b/samples/sharedcontent/run-azurite.sh new file mode 100644 index 0000000..f0939ee --- /dev/null +++ b/samples/sharedcontent/run-azurite.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Instructions to run this script: +# 1. Make sure you have Azurite installed. You can install it using npm: +# npm install -g azurite +# 2. Make sure you have the .NET SDK installed and the `dotnet` command available in your PATH. +# 3. Give execution permissions to this file with the following command: +# chmod +x run-test.sh +# 4. Run the script with the following command: +# ./run-test.sh + +echo "Starting Azurite..." +azurite -s -l /path/to/azurite -d /path/to/azurite/debug.log & + +echo "Running tests..." +dotnet test