├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── build.yml ├── .gitignore ├── CONTRIBUTING.md ├── Directory.Packages.props ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── SkipStrongName.ps1 ├── build.ps1 ├── buildAll.proj ├── code.sln ├── nuget.config ├── nuget └── NuGet.exe ├── nuprojs ├── SF.AspNetCore.Internal │ └── SF.AspNetCore.Internal.nuproj └── packages.config ├── properties ├── Key.snk ├── service_fabric_common.props ├── service_fabric_managed.targets ├── service_fabric_managed_common.props ├── service_fabric_managed_stylecop.props ├── service_fabric_nuget.props ├── service_fabric_nuget.targets └── stylecop │ ├── StylecopSuppressions.cs │ └── stylecop.json ├── refs └── readme.txt ├── src ├── Microsoft.ServiceFabric.AspNetCore.Configuration │ ├── Microsoft.ServiceFabric.AspNetCore.Configuration.csproj │ ├── SR.Designer.cs │ ├── SR.resx │ ├── ServiceFabricConfigurationExtensions.cs │ ├── ServiceFabricConfigurationOptions.cs │ ├── ServiceFabricConfigurationProvider.cs │ └── ServiceFabricConfigurationSource.cs ├── Microsoft.ServiceFabric.AspNetCore.HttpSys │ ├── HttpSysCommunicationListener.cs │ ├── Microsoft.ServiceFabric.AspNetCore.HttpSys.csproj │ ├── SR.Designer.cs │ └── SR.resx ├── Microsoft.ServiceFabric.AspNetCore.Kestrel │ ├── KestrelCommunicationListener.cs │ ├── Microsoft.ServiceFabric.AspNetCore.Kestrel.csproj │ ├── SR.Designer.cs │ └── SR.resx └── Microsoft.ServiceFabric.AspNetCore │ ├── ApplicationBuilderExtensions.cs │ ├── AspNetCoreCommunicationListener.cs │ ├── Friend.cs │ ├── GenericHostCommunicationListener.cs │ ├── Microsoft.ServiceFabric.AspNetCore.csproj │ ├── PathStringExtensions.cs │ ├── SR.Designer.cs │ ├── SR.resx │ ├── ServiceFabricIntegrationOptions.cs │ ├── ServiceFabricMiddleware.cs │ ├── ServiceFabricReverseProxyIntegrationMiddleware.cs │ ├── ServiceFabricSetupFilter.cs │ ├── WebHostBuilderServiceFabricExtension.cs │ └── WebHostCommunicationListener.cs └── test └── unittests ├── Microsoft.ServiceFabric.AspNetCore.Tests ├── AspNetCoreCommunicationListenerTests.cs ├── HttpSysCommunicationListenerTests.cs ├── KestrelCommunicationListenerTests.cs ├── KeyedCollectionImpl.cs ├── Microsoft.ServiceFabric.AspNetCore.Tests.csproj ├── Mocks │ ├── MockConfigurationPackage.cs │ ├── MockConfigurationProperties.cs │ ├── MockConfigurationSections.cs │ ├── TestCodePackageActivationContext.cs │ └── TestHelper.cs ├── ServiceFabricConfigurationProviderTest.cs ├── ServiceFabricMiddlewareTests.cs ├── TestMocksRepository.cs ├── WebHostBuilderServiceFabricExtensionTests.cs └── stylecop.json └── default.runsettings /.editorconfig: -------------------------------------------------------------------------------- 1 | ############################### 2 | # Core EditorConfig Options # 3 | ############################### 4 | root = true 5 | 6 | # All files 7 | [*] 8 | indent_style = space 9 | end_of_line = crlf 10 | end_of_file = crlf 11 | 12 | # Code files 13 | [*.{cs,csx,vb,vbx}] 14 | indent_size = 4 15 | insert_final_newline = true 16 | charset = utf-8 17 | 18 | # Xml build files 19 | [*.builds] 20 | indent_size = 2 21 | 22 | # Xml files 23 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct,xml,stylecop}] 24 | indent_size = 2 25 | 26 | # Xml project files 27 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 28 | indent_size = 2 29 | 30 | # Json files 31 | [*.json] 32 | indent_size = 2 33 | 34 | # C++ Files 35 | [*.{cpp,h,in}] 36 | curly_bracket_next_line = true 37 | indent_brace_style = Allman 38 | 39 | # Shell scripts 40 | [*.sh] 41 | end_of_line = lf 42 | [*.{cmd, bat}] 43 | end_of_line = crlf 44 | 45 | ############################### 46 | # .NET OSS Coding Conventions # 47 | ############################### 48 | [*.{cs,vb}] 49 | # Organize usings 50 | dotnet_sort_system_directives_first = true 51 | 52 | # Use this. 53 | dotnet_style_qualification_for_field = true:warning 54 | dotnet_style_qualification_for_property = true:warning 55 | dotnet_style_qualification_for_method = true:warning 56 | dotnet_style_qualification_for_event = true:warning 57 | 58 | # Use language keywords instead of BCL types 59 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 60 | dotnet_style_predefined_type_for_member_access = true:suggestion 61 | 62 | # Expression-level preferences 63 | dotnet_style_object_initializer = true:none 64 | dotnet_style_collection_initializer = true:none 65 | dotnet_style_explicit_tuple_names = true:suggestion 66 | dotnet_style_null_propagation = false:error 67 | dotnet_style_coalesce_expression = true:suggestion 68 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:none 69 | dotnet_style_require_accessibility_modifiers = always:suggestion 70 | dotnet_prefer_inferred_tuple_names = true:suggestion 71 | dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion 72 | 73 | [*.cs] 74 | # Expression-bodied members 75 | csharp_style_expression_bodied_methods = false:none 76 | csharp_style_expression_bodied_constructors = false:none 77 | csharp_style_expression_bodied_operators = false:none 78 | 79 | # SF-OSS: changed from true to false 80 | csharp_style_expression_bodied_properties = false:none 81 | 82 | csharp_style_expression_bodied_indexers = true:none 83 | csharp_style_expression_bodied_accessors = true:none 84 | 85 | # Pattern matching 86 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 87 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 88 | csharp_style_inlined_variable_declaration = true:suggestion 89 | 90 | # Null-checking preferences 91 | csharp_style_throw_expression = false:none 92 | csharp_style_conditional_delegate_call = false:none 93 | 94 | # Expression-level preferences 95 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion 96 | 97 | [*.vb] 98 | visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion 99 | 100 | ############################### 101 | # .NET Formatting Rules # 102 | ############################### 103 | [*.cs] 104 | # New line preferences 105 | csharp_new_line_before_open_brace = all 106 | csharp_new_line_before_else = true 107 | csharp_new_line_before_catch = true 108 | csharp_new_line_before_finally = true 109 | csharp_new_line_before_members_in_object_initializers = true 110 | csharp_new_line_before_members_in_anonymous_types = true 111 | csharp_new_line_between_query_expression_clauses = true 112 | 113 | # Indentation preferences 114 | csharp_indent_case_contents = true 115 | csharp_indent_switch_labels = true 116 | csharp_indent_labels = flush_left 117 | 118 | # Space preferences 119 | csharp_space_after_cast = false 120 | csharp_space_after_keywords_in_control_flow_statements = true 121 | csharp_space_between_method_call_parameter_list_parentheses = false 122 | csharp_space_between_method_declaration_parameter_list_parentheses = false 123 | csharp_space_between_parentheses = false 124 | 125 | ############################### 126 | # Roslyn-Specific Conventions # 127 | ############################### 128 | # Always use var 129 | csharp_style_var_for_built_in_types = true:suggestion 130 | csharp_style_var_when_type_is_apparent = true:suggestion 131 | csharp_style_var_elsewhere = true:suggestion 132 | 133 | # Expression-level preferences 134 | csharp_prefer_braces = true:suggestion 135 | csharp_style_deconstructed_variable_declaration = true:suggestion 136 | csharp_prefer_simple_default_expression = true:suggestion 137 | csharp_style_pattern_local_over_anonymous_function = true:none 138 | 139 | ############################### 140 | # Naming Conventions # 141 | ############################### 142 | 143 | # Style Definitions 144 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 145 | 146 | dotnet_naming_style.camel_case_style.capitalization = camel_case 147 | 148 | dotnet_naming_style.I_prefix_style.required_prefix = I 149 | dotnet_naming_style.I_prefix_style.capitalization = pascal_case 150 | 151 | # Use PascalCase for constant fields 152 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = warning 153 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields 154 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style 155 | dotnet_naming_symbols.constant_fields.applicable_kinds = field 156 | dotnet_naming_symbols.constant_fields.applicable_accessibilities = * 157 | dotnet_naming_symbols.constant_fields.required_modifiers = const 158 | 159 | # Use PascalCase for static fields 160 | dotnet_naming_rule.static_fields_should_be_pascal_case.severity = warning 161 | dotnet_naming_rule.static_fields_should_be_pascal_case.symbols = static_fields 162 | dotnet_naming_rule.static_fields_should_be_pascal_case.style = pascal_case_style 163 | dotnet_naming_symbols.static_fields.applicable_kinds = field 164 | dotnet_naming_symbols.static_fields.applicable_accessibilities = * 165 | dotnet_naming_symbols.static_fields.required_modifiers = static 166 | 167 | # Use PascalCase for public fields 168 | dotnet_naming_rule.pascal_case_for_public_fields.severity = warning 169 | dotnet_naming_rule.pascal_case_for_public_fields.symbols = public_fields 170 | dotnet_naming_rule.pascal_case_for_public_fields.style = pascal_case_style 171 | dotnet_naming_symbols.public_fields.applicable_kinds = field 172 | dotnet_naming_symbols.public_fields.applicable_accessibilities = public 173 | 174 | # Use camelCase for all other fields 175 | dotnet_naming_rule.camel_case_for_other_fields.severity = warning 176 | dotnet_naming_rule.camel_case_for_other_fields.symbols = other_fields 177 | dotnet_naming_rule.camel_case_for_other_fields.style = camel_case_style 178 | dotnet_naming_symbols.other_fields.applicable_kinds = field 179 | dotnet_naming_symbols.other_fields.applicable_accessibilities = * 180 | 181 | # Interfaces must be PascalCase and have an I prefix 182 | dotnet_naming_rule.interfaces_start_with_I.severity = warning 183 | dotnet_naming_rule.interfaces_start_with_I.symbols = any_interface 184 | dotnet_naming_rule.interfaces_start_with_I.style = I_prefix_style 185 | dotnet_naming_symbols.any_interface.applicable_accessibilities = * 186 | dotnet_naming_symbols.any_interface.applicable_kinds = interface 187 | 188 | # Classes, structs, methods, enums, events, properties, namespaces, delegates must be PascalCase 189 | dotnet_naming_rule.general_naming.severity = warning 190 | dotnet_naming_rule.general_naming.symbols = general 191 | dotnet_naming_rule.general_naming.style = pascal_case_style 192 | dotnet_naming_symbols.general.applicable_kinds = class,struct,enum,property,method,event,namespace,delegate 193 | dotnet_naming_symbols.general.applicable_accessibilities = * 194 | 195 | # Everything else is camelCase 196 | dotnet_naming_rule.everything_else_naming.severity = warning 197 | dotnet_naming_rule.everything_else_naming.symbols = everything_else 198 | dotnet_naming_rule.everything_else_naming.style = camel_case_style 199 | dotnet_naming_symbols.everything_else.applicable_kinds = * 200 | dotnet_naming_symbols.everything_else.applicable_accessibilities = * 201 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps or code snippet to reproduce the behavior. 12 | 13 | **Expected behavior** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Additional context** 17 | Add any other context about the problem here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - 'release_*' 8 | 9 | pull_request: 10 | branches: 11 | - develop 12 | - 'release_*' 13 | 14 | jobs: 15 | build: 16 | name: Build Test 17 | runs-on: windows-latest 18 | # info about windows-latest https://github.com/actions/runner-images 19 | env: 20 | DROP_DIR: drop 21 | TEST_RESULT_DIR: drop\testresults 22 | steps: 23 | - uses: actions/checkout@v1 24 | - name: Setup dotnet 25 | uses: actions/setup-dotnet@v4 26 | with: 27 | dotnet-version: '9.0.x' 28 | - name: Build Everything 29 | shell: powershell 30 | run: dotnet build buildAll.proj 31 | - name: Run Tests 32 | run: dotnet test code.sln --configuration release --nologo --settings test\unittests\default.runsettings --results-directory ${{ env.TEST_RESULT_DIR }} --logger trx 33 | - name: upload artifacts 34 | uses: actions/upload-artifact@master 35 | with: 36 | name: release_drop 37 | path: ${{ env.DROP_DIR }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Everything in the external/packages directory as nuget packages are restored here. 3 | /nuget/restored_packages/* 4 | 5 | # Build generated files in src 6 | /src/**/objd/**/* 7 | /src/**/obj/**/* 8 | /src/**/bin/**/* 9 | /src/**/gen/**/* 10 | /src/**/*.nuspec 11 | /src/**/StyleCop.Cache 12 | 13 | # MSBuild's log file 14 | msbuild.log 15 | 16 | # Build.exe 17 | *.err 18 | *.wrn 19 | *.log 20 | *.prf 21 | *.trc 22 | buildd.dbb 23 | build.dbb 24 | buildd.evt 25 | build.evt 26 | 27 | ### 28 | Repository Bloat Risks 29 | ### 30 | *.exe 31 | *.dll 32 | *.lib 33 | *.pdb 34 | *.wim 35 | *.zip 36 | *.gz 37 | *.meta 38 | *.obj 39 | *.tmp 40 | *.tmp_proj 41 | *.log 42 | .builds 43 | 44 | ## Ignore Visual Studio temporary files, build results, and 45 | ## files generated by popular Visual Studio add-ons. 46 | *.vs/ 47 | 48 | # User-specific files 49 | *.suo 50 | *.user 51 | *.userosscache 52 | *.sln.docstates 53 | 54 | # Build results 55 | [Dd]ebug/ 56 | [Dd]ebugPublic/ 57 | [Rr]elease/ 58 | [Rr]eleases/ 59 | x64/ 60 | x86/ 61 | build/ 62 | bld/ 63 | [Bb]in/ 64 | [Oo]bj/ 65 | 66 | #drop folder 67 | /src/drop/**/* 68 | 69 | # Roslyn cache directories 70 | *.ide/ 71 | 72 | # Visual Studio profiler 73 | *.psess 74 | *.vsp 75 | *.vspx 76 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing code and content 2 | We welcome all forms of contributions from the community. Please read the following guidelines to maximize the chances of your PR being merged. 3 | 4 | ### Reporting security issues and bugs 5 | Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) secure@microsoft.com. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the [Security TechCenter](https://technet.microsoft.com/en-us/security/ff852094.aspx). 6 | 7 | ### Other discussions 8 | For general "how-to" and guidance questions about using Service Fabric to build and run applications, please use [Stack Overflow](http://stackoverflow.com/questions/tagged/azure-service-fabric) tagged with `azure-service-fabric`. 9 | 10 | ### Development process 11 | Please be sure to follow the usual process for submitting PRs: 12 | 13 | - Fork the repo 14 | - Create a pull request into correct branch (see branching information below). 15 | - Make sure your PR title is descriptive 16 | - Include a link back to an open issue in the PR description 17 | 18 | We reserve the right to close PRs that are not making progress. If no changes are made for 7 days, we'll close the PR. Closed PRs can be reopened again later and work can resume. 19 | 20 | ### Branching Information 21 | All development for future releases happen in the develop branch. 22 | A new branch is forked off of develop branch for each release to stabilize it before final release. (eg. release_4.0 branch represents the 4.0.* release). 23 | A bug fix in an already released version is made both to its release branch and to develop branch so that its available in refresh of the release and for future new releases. 24 | 25 | ### Contributor License Agreement 26 | Before you submit a pull request, a bot will prompt you to sign the [Microsoft Contributor License Agreement](https://cla.microsoft.com/). This needs to be done only once for any Microsoft-sponsored open source project - if you've signed the Microsoft CLA for any project sponsored by Microsoft, then you are good to go for all the repos sponsored by Microsoft. 27 | 28 | > **Important**: Note that there are **two** different CLAs commonly used by Microsoft projects: [Microsoft CLA](https://cla.microsoft.com/) and [.NET Foundation CLA](https://cla2.dotnetfoundation.org/). Service Fabric open source projects use the [Microsoft](https://cla.microsoft.com/) CLA. The .NET Foundation is treated as a separate entity, so if you've signed the .NET Foundation CLA in the past, you will still need to sign the Microsoft CLA to contribute to Service Fabric open source projects. 29 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | 6 | 7 | 8 | 9 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Service Fabric Reliable Services ASP.NET Core Integration 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | All rights reserved. 6 | 7 | MIT License 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure/service-fabric-aspnetcore 2 | 3 | This repo contains ASP.NET Core integration for Service Fabric Reliable Services. 4 | 5 | The `Microsoft.ServiceFabric.Services.AspNetCore.*` NuGet packages contain implementations of `ICommunicationListener` that start the ASP.NET Core web host for either Kestrel or HttpSys in a Service Fabric Reliable Service. The `ICommunicationListener` allows you to configure `IWebHost`, and then it manages its lifetime. 6 | 7 | This repo builds the following packages: 8 | - Microsoft.ServiceFabric.AspNetCore.Abstractions 9 | - Microsoft.ServiceFabric.AspNetCore.HttpSys 10 | - Microsoft.ServiceFabric.AspNetCore.Kestrel 11 | - Microsoft.ServiceFabric.AspNetCore.Configuration 12 | 13 | These packages are documented [here](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-aspnetcore). 14 | 15 | ## Getting Started 16 | 17 | ### Prerequesites 18 | Each project is a normal C# Visual Studio project. At minimum, you need [MSBuild 16](https://docs.microsoft.com/en-us/visualstudio/msbuild/whats-new-msbuild-16-0), [PowerShell](https://msdn.microsoft.com/powershell/mt173057.aspx), [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) and [.NET Framework 4.6](https://www.microsoft.com/en-US/download/details.aspx?id=48130) to build and generate NuGet packages. 19 | 20 | We recommend installing Visual Studio 2022 which will set you up with all the .NET build tools and allow you to open the solution files. Currently VS 2022 is in preview which can also be used to build everything here. 21 | 22 | ### Build 23 | To build everything and generate NuGet packages, run the **build.ps1** script. NuGet packages will be dropped in a *drop* directory at the repo root. 24 | 25 | Each project can also be built individually directly through Visual Studio or by running the solution file through MSBuild. 26 | 27 | Binaries in the build are delay signed, these are fully signed in the official builds released by Microsoft. To use the binaries or to run unit tests from the build of this repository, strong name validation needs to be skipped for these assemblies. This can be done by running **SkipStrongName.ps1** script available in the root of the repository. 28 | 29 | For branches, please see [Branching Information](CONTRIBUTING.md#BranchingInformation) 30 | 31 | ## Development 32 | We are currently working on transitioning all development to GitHub. For the time being we are continuing to do our own development internally. Upon each release of the SDK, we will push our latest changes to GitHub. We intend to bring more of our development process and tools into the open over time. 33 | 34 | ## Releases and Support 35 | Official releases from Microsoft of the NuGet packages in this repo are released directly to NuGet and Web Platform Installer. Get the latest official release [here](http://www.microsoft.com/web/handlers/webpi.ashx?command=getinstallerredirect&appid=MicrosoftAzure-ServiceFabric-VS2015). 36 | 37 | **Only officially released NuGet packages from Microsoft are supported for use in production.** If you have a feature or bug fix that you would like to use in your application, please issue a pull request so we can get it into an official release. 38 | 39 | ## Reporting issues and feedback 40 | Please refer to [Contributing.md](https://github.com/Microsoft/service-fabric/blob/master/CONTRIBUTING.md) at the Service Fabric home repo for details on issue reporting and feedback. 41 | 42 | ## Contributing code 43 | If you would like to become an active contributor to this project please 44 | follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.io/guidelines.html). For details, please refer to [Contributing.md](CONTRIBUTING.md). 45 | 46 | ## Documentation 47 | Service Fabric has a rich set of conceptual and reference documentation available at [https://docs.microsoft.com/azure/service-fabric](https://docs.microsoft.com/azure/service-fabric). 48 | 49 | The ASP.NET Core integration packages are documented at [https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-aspnetcore](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-communication-aspnetcore). 50 | 51 | ## Samples 52 | For Service Fabric sample code, check out the [Azure Code Sample gallery](https://azure.microsoft.com/en-us/resources/samples/?service=service-fabric) or go straight to [Azure-Samples on GitHub](https://github.com/Azure-Samples?q=service-fabric). 53 | 54 | ## License 55 | [MIT](License.txt) 56 | 57 | --- 58 | *This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.* 59 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SkipStrongName.ps1: -------------------------------------------------------------------------------- 1 | # Register assemblies for strong name verification skipping 2 | 3 | $registryPath = "HKLM:\SOFTWARE\Microsoft\StrongName\Verification" 4 | $publicKeyToken="31bf3856ad364e35" 5 | $assemblies = "Microsoft.ServiceFabric.AspNetCore", 6 | "Microsoft.ServiceFabric.AspNetCore.Configuration", 7 | "Microsoft.ServiceFabric.AspNetCore.HttpSys", 8 | "Microsoft.ServiceFabric.AspNetCore.Kestrel", 9 | "Microsoft.ServiceFabric.AspNetCore.Tests" 10 | 11 | Write-Host "Registering assemblies generated by this repository for strong name verification skipping." 12 | foreach ($assembly in $assemblies) 13 | { 14 | $assemblyIdentity = "$assembly,$publicKeyToken" 15 | New-Item -Path "$registryPath\$assemblyIdentity" -Force | Out-Null 16 | } 17 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | ## 2 | # Builds the source code and generates nuget packages. You can optionally just build the source code by opening individual solutions in Visual Studio. 3 | ## 4 | 5 | param 6 | ( 7 | # Configuration to build. 8 | [ValidateSet('Debug', 'Release')] 9 | [string]$Configuration = "Release", 10 | 11 | # target to build. 12 | #Options are: 13 | # RebuildAll: Clean, Build all .csproj and Generate Nuget Packages. This is the default option. 14 | # BuildAll: Build all .csproj and Generate Nuget Packages. 15 | # BuildCode: Builds code, doesn't generates nuget packages. 16 | # GeneratePackages: Generates nuget packages, this target doesn't builds code, build must be done using BuildCode target before invoking this target. 17 | [ValidateSet('Rebuildall', 'BuildAll', 'BuildCode', 'GeneratePackages')] 18 | [string]$Target = "RebuildAll", 19 | 20 | # msbuild verbosity level. 21 | [ValidateSet('quiet','minimal', 'normal', 'detailed', 'diagnostic')] 22 | [string]$Verbosity = 'minimal', 23 | 24 | # path to msbuild 25 | [string]$MSBuildFullPath 26 | ) 27 | 28 | if($MSBuildFullPath -ne "") 29 | { 30 | if (!(Test-Path $MSBuildFullPath)) 31 | { 32 | throw "Unable to find MSBuild at the specified path, run the script again with correct path to msbuild." 33 | } 34 | } 35 | 36 | # msbuild path not provided, find msbuild for VS2022 37 | if($MSBuildFullPath -eq "") 38 | { 39 | $progFilesPaths = ${env:\ProgramFiles(x86)}, ${env:\ProgramFiles} 40 | foreach ($progFilesPath in $progFilesPaths) 41 | { 42 | $VS2022InstallPath = join-path $progFilesPath "Microsoft Visual Studio\2022" 43 | $versions = 'Preview', 'Community', 'Professional', 'Enterprise' 44 | 45 | foreach ($version in $versions) 46 | { 47 | $VS2022VersionPath = join-path $VS2022InstallPath $version 48 | $testPath = join-path $VS2022VersionPath "MSBuild\Current\Bin\MSBuild.exe" 49 | 50 | if (Test-Path $testPath) 51 | { 52 | $MSBuildFullPath = $testPath 53 | } 54 | } 55 | } 56 | } 57 | 58 | if (!(Test-Path $MSBuildFullPath)) 59 | { 60 | throw "Unable to find MSBuild installed on this machine. Please install Visual Studio 2022 or if its installed at non-default location, provide the full path to msbuild using -MSBuildFullPath parameter." 61 | } 62 | 63 | 64 | Write-Output "Using msbuild from $msbuildFullPath" 65 | 66 | $msbuildArgs = @("buildall.proj", "/nr:false", "/nologo", "/t:$target", "/verbosity:$verbosity", "/property:RequestedVerbosity=$verbosity", "/property:Configuration=$configuration", $args) 67 | & $msbuildFullPath $msbuildArgs -------------------------------------------------------------------------------- /buildAll.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | $(MSBuildThisFileDirectory) 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /code.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34221.43 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ServiceFabric.AspNetCore", "src\Microsoft.ServiceFabric.AspNetCore\Microsoft.ServiceFabric.AspNetCore.csproj", "{A45918E1-6345-432E-AD6D-47DEEFB35661}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ServiceFabric.AspNetCore.HttpSys", "src\Microsoft.ServiceFabric.AspNetCore.HttpSys\Microsoft.ServiceFabric.AspNetCore.HttpSys.csproj", "{7BE05428-AD27-41CB-B01A-85821B69175F}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ServiceFabric.AspNetCore.Kestrel", "src\Microsoft.ServiceFabric.AspNetCore.Kestrel\Microsoft.ServiceFabric.AspNetCore.Kestrel.csproj", "{B80B46C9-759A-4C5B-8618-C7A45395D9A2}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{BC6C4F04-5CED-4AB6-930B-3348145E6316}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ServiceFabric.AspNetCore.Tests", "test\unittests\Microsoft.ServiceFabric.AspNetCore.Tests\Microsoft.ServiceFabric.AspNetCore.Tests.csproj", "{F9D9E1BB-212D-4785-8E1E-8427355AAF68}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0371241A-7255-4C77-AE01-00B80954DC23}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{BA7A4C8B-A2B3-4349-878D-4AB5681B9FA6}" 19 | ProjectSection(SolutionItems) = preProject 20 | .editorconfig = .editorconfig 21 | EndProjectSection 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.ServiceFabric.AspNetCore.Configuration", "src\Microsoft.ServiceFabric.AspNetCore.Configuration\Microsoft.ServiceFabric.AspNetCore.Configuration.csproj", "{99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}" 24 | EndProject 25 | Global 26 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 27 | Debug|Any CPU = Debug|Any CPU 28 | Debug|x64 = Debug|x64 29 | Release|Any CPU = Release|Any CPU 30 | Release|x64 = Release|x64 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {A45918E1-6345-432E-AD6D-47DEEFB35661}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {A45918E1-6345-432E-AD6D-47DEEFB35661}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {A45918E1-6345-432E-AD6D-47DEEFB35661}.Debug|x64.ActiveCfg = Debug|x64 36 | {A45918E1-6345-432E-AD6D-47DEEFB35661}.Debug|x64.Build.0 = Debug|x64 37 | {A45918E1-6345-432E-AD6D-47DEEFB35661}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {A45918E1-6345-432E-AD6D-47DEEFB35661}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {A45918E1-6345-432E-AD6D-47DEEFB35661}.Release|x64.ActiveCfg = Release|x64 40 | {A45918E1-6345-432E-AD6D-47DEEFB35661}.Release|x64.Build.0 = Release|x64 41 | {7BE05428-AD27-41CB-B01A-85821B69175F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {7BE05428-AD27-41CB-B01A-85821B69175F}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {7BE05428-AD27-41CB-B01A-85821B69175F}.Debug|x64.ActiveCfg = Debug|x64 44 | {7BE05428-AD27-41CB-B01A-85821B69175F}.Debug|x64.Build.0 = Debug|x64 45 | {7BE05428-AD27-41CB-B01A-85821B69175F}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {7BE05428-AD27-41CB-B01A-85821B69175F}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {7BE05428-AD27-41CB-B01A-85821B69175F}.Release|x64.ActiveCfg = Release|x64 48 | {7BE05428-AD27-41CB-B01A-85821B69175F}.Release|x64.Build.0 = Release|x64 49 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2}.Debug|x64.ActiveCfg = Debug|x64 52 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2}.Debug|x64.Build.0 = Debug|x64 53 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2}.Release|Any CPU.Build.0 = Release|Any CPU 55 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2}.Release|x64.ActiveCfg = Release|x64 56 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2}.Release|x64.Build.0 = Release|x64 57 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 58 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68}.Debug|Any CPU.Build.0 = Debug|Any CPU 59 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68}.Debug|x64.ActiveCfg = Debug|x64 60 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68}.Debug|x64.Build.0 = Debug|x64 61 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68}.Release|Any CPU.ActiveCfg = Release|Any CPU 62 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68}.Release|Any CPU.Build.0 = Release|Any CPU 63 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68}.Release|x64.ActiveCfg = Release|x64 64 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68}.Release|x64.Build.0 = Release|x64 65 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 66 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}.Debug|Any CPU.Build.0 = Debug|Any CPU 67 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}.Debug|x64.ActiveCfg = Debug|x64 68 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}.Debug|x64.Build.0 = Debug|x64 69 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}.Release|Any CPU.ActiveCfg = Release|Any CPU 70 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}.Release|Any CPU.Build.0 = Release|Any CPU 71 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}.Release|x64.ActiveCfg = Release|x64 72 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780}.Release|x64.Build.0 = Release|x64 73 | EndGlobalSection 74 | GlobalSection(SolutionProperties) = preSolution 75 | HideSolutionNode = FALSE 76 | EndGlobalSection 77 | GlobalSection(NestedProjects) = preSolution 78 | {A45918E1-6345-432E-AD6D-47DEEFB35661} = {0371241A-7255-4C77-AE01-00B80954DC23} 79 | {7BE05428-AD27-41CB-B01A-85821B69175F} = {0371241A-7255-4C77-AE01-00B80954DC23} 80 | {B80B46C9-759A-4C5B-8618-C7A45395D9A2} = {0371241A-7255-4C77-AE01-00B80954DC23} 81 | {F9D9E1BB-212D-4785-8E1E-8427355AAF68} = {BC6C4F04-5CED-4AB6-930B-3348145E6316} 82 | {99AEA1AC-AA3B-426D-A0BE-2B2FAB68C780} = {0371241A-7255-4C77-AE01-00B80954DC23} 83 | EndGlobalSection 84 | GlobalSection(ExtensibilityGlobals) = postSolution 85 | SolutionGuid = {2CDABF99-A026-479B-B672-736D0A8C9A37} 86 | EndGlobalSection 87 | EndGlobal 88 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/service-fabric-aspnetcore/c8221f6d5610d8dabb808a273bdcf31cfbb00af5/nuget/NuGet.exe -------------------------------------------------------------------------------- /nuprojs/SF.AspNetCore.Internal/SF.AspNetCore.Internal.nuproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SF.AspNetCore.Internal 7 | SF.AspNetCore.Internal 8 | This package provides Service Fabric AspNetCore integration libraries for consumption by other Service Fabric repos. 9 | This package provides Service Fabric AspNetCore integration libraries for consumption by other Service Fabric repos. 10 | ServiceFabric Microsoft Azure Fabric 11 | v4.8.1 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | lib\netframework 20 | 21 | 22 | lib\net8.0 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /nuprojs/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /properties/Key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/service-fabric-aspnetcore/c8221f6d5610d8dabb808a273bdcf31cfbb00af5/properties/Key.snk -------------------------------------------------------------------------------- /properties/service_fabric_common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | $([System.String]::Copy('$(MSBuildThisFileDirectory)').Replace('properties\','')) 8 | minimal 9 | 10 | 11 | bin\$(Configuration)\ 12 | 13 | 14 | $(RepoRoot)drop\$(Configuration)\ 15 | $(RepoRoot)drop\$(Configuration)\net462\ 16 | $(RepoRoot)drop\$(Configuration)\net8.0\ 17 | $(DropFolder)\packages 18 | 19 | 20 | $(RepoRoot)\nuget\nuget.exe 21 | 22 | 23 | 24 | 9 25 | 0 26 | 0 27 | 0 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /properties/service_fabric_managed.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /properties/service_fabric_managed_common.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | AnyCPU 8 | true 9 | 4 10 | 11 | 12 | true 13 | AnyCPU 14 | 15 | 16 | 17 | 18 | true 19 | 20 | 21 | 22 | 23 | full 24 | 25 | 26 | pdbonly 27 | 28 | 29 | 30 | 31 | true 32 | 33 | 34 | 35 | 36 | false 37 | 38 | 39 | 40 | 41 | true 42 | true 43 | $(MSBuildThisFileDirectory)Key.snk 44 | 45 | 46 | 47 | 48 | 6.0.0.0 49 | $(MajorVersion).$(MinorVersion).$(BuildVersion).$(Revision) 50 | $(MajorVersion).$(MinorVersion).$(BuildVersion).$(Revision) 51 | $(MajorVersion).$(MinorVersion).$(BuildVersion).$(Revision) 52 | 53 | 54 | 55 | Microsoft Azure Service Fabric 56 | Copyright (c) Microsoft Corporation. All rights reserved. 57 | Microsoft 58 | Microsoft 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /properties/service_fabric_managed_stylecop.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildThisFileDirectory)stylecop\stylecop.json 5 | $(MSBuildThisFileDirectory)stylecop\StylecopSuppressions.cs 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /properties/service_fabric_nuget.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | $(MajorVersion).$(MinorVersion).$(BuildVersion) 8 | 9 | 10 | 11 | Microsoft 12 | Microsoft,ServiceFabric 13 | http://aka.ms/servicefabric 14 | http://www.microsoft.com/web/webpi/eula/net_library_eula_ENU.htm 15 | © Microsoft Corporation. All rights reserved. 16 | True 17 | true 18 | ServiceFabric Microsoft Azure Fabric 19 | http://go.microsoft.com/fwlink/?LinkID=288890 20 | en-US 21 | $(OutputRoot)\packages 22 | 23 | 24 | $(NuGetPackageVersion) 25 | False 26 | 27 | 28 | 29 | 30 | $(RepoRoot)\nuget\restored_packages\NuProj.0.11.30\tools 31 | 32 | 33 | -------------------------------------------------------------------------------- /properties/service_fabric_nuget.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /properties/stylecop/StylecopSuppressions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | [assembly: SuppressMessage( 9 | "StyleCop.CSharp.MaintainabilityRules", 10 | "SA1119:StatementMustNotUseUnnecessaryParenthesis", 11 | Justification = "The code is more redable, especially when using parenthesis for the return statements.")] 12 | 13 | [assembly: SuppressMessage( 14 | "StyleCop.CSharp.ReadabilityRules", 15 | "SA1124:DoNotUseRegions", 16 | Justification = "In large files region allows creating logical sections in the file for better readability.")] 17 | 18 | [assembly: SuppressMessage( 19 | "Style", 20 | "IDE1006:Naming Styles", 21 | Justification = "Prefer SA1307-SA1307AccessibleFieldsMustBeginWithUpperCaseLetter over IDE:1006.")] 22 | -------------------------------------------------------------------------------- /properties/stylecop/stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | // ACTION REQUIRED: This file was automatically added to your project, but it 3 | // will not take effect until additional steps are taken to enable it. See the 4 | // following page for additional information: 5 | // 6 | // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md 7 | 8 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 9 | "settings": { 10 | "documentationRules": { 11 | "companyName": "Microsoft Corporation", 12 | "copyrightText": "------------------------------------------------------------\nCopyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} License ({licenseName}). See {licenseFile} in the repo root for license information.\n------------------------------------------------------------", 13 | "variables": { 14 | "licenseName": "MIT", 15 | "licenseFile": "License.txt" 16 | }, 17 | "xmlHeader": false, 18 | "documentInternalElements": false 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /refs/readme.txt: -------------------------------------------------------------------------------- 1 | Service Fabric pre-release nuget packages from other branches can be checked in here for develop branch until its officially released. -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Configuration/Microsoft.ServiceFabric.AspNetCore.Configuration.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Microsoft.ServiceFabric.AspNetCore.Configuration 7 | Microsoft.ServiceFabric.AspNetCore.Configuration 8 | $(OutputPath)\$(AssemblyName).xml 9 | net462;net8.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | True 23 | True 24 | SR.resx 25 | 26 | 27 | 28 | 29 | ResXFileCodeGenerator 30 | SR.Designer.cs 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Configuration/SR.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Microsoft.ServiceFabric.AspNetCore.Configuration { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class SR { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal SR() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.ServiceFabric.AspNetCore.Configuration.SR", typeof(SR).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Configuration/SR.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Configuration/ServiceFabricConfigurationExtensions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Configuration 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Fabric; 11 | using System.Text; 12 | using Microsoft.Extensions.Configuration; 13 | 14 | /// 15 | /// Configuration extentions to add service fabric configuration. 16 | /// 17 | public static class ServiceFabricConfigurationExtensions 18 | { 19 | /// 20 | /// Add configuration for all the configuration packages declared for current service. 21 | /// 22 | /// the configuration builder. 23 | /// the same configuration builder with service fabric configuration added. 24 | public static IConfigurationBuilder AddServiceFabricConfiguration(this IConfigurationBuilder builder) 25 | { 26 | if (builder == null) 27 | { 28 | throw new ArgumentNullException(nameof(builder)); 29 | } 30 | 31 | ICodePackageActivationContext activationContext = FabricRuntime.GetActivationContext(); 32 | 33 | // DO NOT dispose activation context as it will be saved to DI container and used later. 34 | // using (activationContext) 35 | { 36 | return builder.AddServiceFabricConfiguration(activationContext); 37 | } 38 | } 39 | 40 | /// 41 | /// Add configuration for all the configuration packages declared for current code package. 42 | /// 43 | /// the configuration builder. 44 | /// the activation context with information for configuration packages. 45 | /// the same configuration builder with service fabric configuration added. 46 | public static IConfigurationBuilder AddServiceFabricConfiguration(this IConfigurationBuilder builder, ICodePackageActivationContext context) 47 | { 48 | return builder.AddServiceFabricConfiguration(context, null); 49 | } 50 | 51 | /// 52 | /// Add configuration for given configuration package from packageName parameter as well as customize config action to populate the Data. 53 | /// 54 | /// the configuration builder. 55 | /// the activation context with information for configuration packages. 56 | /// the delegate to change the configuration options including configuration actions. 57 | /// the same configuration builder with service fabric configuration added. 58 | public static IConfigurationBuilder AddServiceFabricConfiguration( 59 | this IConfigurationBuilder builder, 60 | ICodePackageActivationContext context, 61 | Action optionsDelegate) 62 | { 63 | if (builder == null) 64 | { 65 | throw new ArgumentNullException(nameof(builder)); 66 | } 67 | 68 | if (context == null) 69 | { 70 | throw new ArgumentNullException(nameof(context)); 71 | } 72 | 73 | var packageNames = context.GetConfigurationPackageNames(); 74 | foreach (var packageName in packageNames) 75 | { 76 | var options = new ServiceFabricConfigurationOptions(packageName); 77 | 78 | if (optionsDelegate != null) 79 | { 80 | optionsDelegate(options); 81 | } 82 | 83 | builder.Add(new ServiceFabricConfigurationSource(context, options)); 84 | } 85 | 86 | return builder; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Configuration/ServiceFabricConfigurationOptions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Configuration 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Fabric; 11 | using System.Fabric.Description; 12 | using System.Runtime.InteropServices; 13 | using Microsoft.Extensions.Configuration; 14 | using FabricConfigurationSection = System.Fabric.Description.ConfigurationSection; 15 | 16 | /// 17 | /// The options used to configure the behavior of mapping configuration package to IConfiguration items. 18 | /// 19 | public class ServiceFabricConfigurationOptions 20 | { 21 | /// 22 | /// Initializes a new instance of the class. 23 | /// 24 | /// the name of the configuration package. 25 | public ServiceFabricConfigurationOptions(string packageName) 26 | { 27 | this.PackageName = packageName ?? throw new ArgumentNullException(packageName); 28 | this.IncludePackageName = true; 29 | this.DecryptValue = false; // secure by default. 30 | 31 | this.ConfigAction = this.DefaultConfigAction; 32 | this.ExtractKeyFunc = this.DefaultExtractKeyFunc; 33 | this.ExtractValueFunc = this.DefaultExtractValueFunc; 34 | } 35 | 36 | /// 37 | /// Gets the name of the configuration package this options is used for. 38 | /// 39 | public string PackageName { get; } 40 | 41 | /// 42 | /// Gets or sets the configuration used to transform the configuration package to IConfiguration items. 43 | /// 44 | /// 45 | /// This is for advanced usage scenario to take data from package and populate into the dictionary. 46 | /// For example, this could be used to populate json configuration files, adding logging for configuration updates, etc. 47 | /// The default value is a delegate which used PackageName, SectionName and ParamName as the key and value as the param value regardless of encrypted or not. 48 | /// 49 | public Action> ConfigAction { get; set; } 50 | 51 | /// 52 | /// Gets or sets the function to extract the IConfiguration key from the fabric configuration section and property. 53 | /// The return value of the fuction would be used as the key for IConfiguration in ConfigAction. 54 | /// 55 | /// 56 | /// The default value is a function which used PackageName, SectionName and ParamName as the key with default IncludePackageName as true. 57 | /// 58 | public Func ExtractKeyFunc { get; set; } 59 | 60 | /// 61 | /// Gets or sets the function to extract the IConfiguration value from the fabric configuration section and property. 62 | /// The return value of the fuction would be used as the value for IConfiguration in ConfigAction. 63 | /// 64 | /// 65 | /// The default value is a function which used the param value regardless of encrypted or not with default DecryptValue flag as true. 66 | /// 67 | public Func ExtractValueFunc { get; set; } 68 | 69 | /// 70 | /// Gets or sets a value indicating whether or not to include the configuration package name to the section name of IConfiguration item. 71 | /// The default is true, and will include the package name, section name and param namein configuraton package. 72 | /// You could set this to true for multiple config packages to avoid a setting with same section name and param name being override from other package. 73 | /// 74 | public bool IncludePackageName { get; set; } 75 | 76 | /// 77 | /// Gets or sets a value indicating whether or not to decypt the encrypted value to unsecure string. 78 | /// 79 | /// 80 | /// A typical safety guideline is to keep encrypted string encrypted in memory, and then decrypt (briefly) at time of use. 81 | /// With this reason, DecryptValue will default to false to treat encrypted value the same as plain text by default, 82 | /// user will need to handle encrypted string separately to compliant with security best practice. 83 | /// 84 | public bool DecryptValue { get; set; } 85 | 86 | internal void DefaultConfigAction(ConfigurationPackage config, IDictionary data) 87 | { 88 | foreach (var section in config.Settings.Sections) 89 | { 90 | foreach (var param in section.Parameters) 91 | { 92 | string key = this.ExtractKeyFunc(section, param); 93 | string value = this.ExtractValueFunc(section, param); 94 | data[key] = value; 95 | } 96 | } 97 | } 98 | 99 | internal string DefaultExtractKeyFunc(FabricConfigurationSection section, ConfigurationProperty property) 100 | { 101 | if (this.IncludePackageName) 102 | { 103 | return $"{this.PackageName}{ConfigurationPath.KeyDelimiter}{section.Name}{ConfigurationPath.KeyDelimiter}{property.Name}"; 104 | } 105 | else 106 | { 107 | return $"{section.Name}{ConfigurationPath.KeyDelimiter}{property.Name}"; 108 | } 109 | } 110 | 111 | internal string DefaultExtractValueFunc(FabricConfigurationSection section, ConfigurationProperty property) 112 | { 113 | // see https://github.com/Azure/service-fabric-aspnetcore/issues/9 114 | // A typical safety guideline is to keep encrypted string encrypted in memory, and then decrypt (briefly) at time of use. 115 | // With this reason, will treat encrypted value the same as plain text by default, 116 | // user will need to handle encrypted string separately to compliant with security best practice. 117 | if (property.IsEncrypted && this.DecryptValue) 118 | { 119 | IntPtr unmanagedString = IntPtr.Zero; 120 | var secureString = property.DecryptValue(); 121 | 122 | try 123 | { 124 | unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString); 125 | return Marshal.PtrToStringUni(unmanagedString); 126 | } 127 | finally 128 | { 129 | Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString); 130 | } 131 | } 132 | else 133 | { 134 | return property.Value; 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Configuration/ServiceFabricConfigurationProvider.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Configuration 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Fabric; 11 | using Microsoft.Extensions.Configuration; 12 | 13 | internal class ServiceFabricConfigurationProvider : ConfigurationProvider 14 | { 15 | private readonly ICodePackageActivationContext context; 16 | private readonly ServiceFabricConfigurationOptions options; 17 | 18 | public ServiceFabricConfigurationProvider(ICodePackageActivationContext activationContext, ServiceFabricConfigurationOptions options) 19 | { 20 | this.context = activationContext; 21 | 22 | this.options = options ?? throw new ArgumentNullException(nameof(options)); 23 | 24 | this.context.ConfigurationPackageModifiedEvent += (sender, e) => 25 | { 26 | this.HandleNewPackage(e.NewPackage); 27 | }; 28 | 29 | this.context.ConfigurationPackageAddedEvent += (sender, e) => 30 | { 31 | this.HandleNewPackage(e.Package); 32 | }; 33 | } 34 | 35 | /// 36 | /// Load the configuration. 37 | /// 38 | public override void Load() 39 | { 40 | var config = this.context.GetConfigurationPackageObject(this.options.PackageName); 41 | this.LoadPackage(config); 42 | } 43 | 44 | /// 45 | /// Handle loading of a new package provided by a ConfigurationPackageModifiedEvent or a ConfigurationPackageAddedEvent. 46 | /// 47 | /// The new package to load from. 48 | private void HandleNewPackage(ConfigurationPackage package) 49 | { 50 | if (package.Description is null) 51 | { 52 | throw new ArgumentNullException($"{nameof(package)}.Description", $"A valid Description must be provided with {nameof(package)}."); 53 | } 54 | 55 | // Load configuration from new package only if it is the ConfigPackage mapped to this provider 56 | if (package.Description.Name == this.options.PackageName) 57 | { 58 | this.LoadPackage(package, reload: true); 59 | this.OnReload(); // Notify the change 60 | } 61 | } 62 | 63 | /// 64 | /// Load and populate data from . 65 | /// 66 | /// The package to load from. 67 | /// Whether or not to completely refresh . 68 | private void LoadPackage(ConfigurationPackage package, bool reload = false) 69 | { 70 | if (reload) 71 | { 72 | this.Data.Clear(); // Remove the old keys on re-load 73 | } 74 | 75 | // call the delegate action to populate the Data 76 | this.options.ConfigAction(package, this.Data); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Configuration/ServiceFabricConfigurationSource.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Configuration 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Fabric; 11 | using Microsoft.Extensions.Configuration; 12 | 13 | internal class ServiceFabricConfigurationSource : IConfigurationSource 14 | { 15 | private readonly ServiceFabricConfigurationOptions options; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// the code package activation context. 21 | /// the configuration options. 22 | public ServiceFabricConfigurationSource(ICodePackageActivationContext activationContext, ServiceFabricConfigurationOptions options) 23 | { 24 | this.ActivationContext = activationContext; 25 | this.options = options; 26 | } 27 | 28 | public ICodePackageActivationContext ActivationContext { get; } 29 | 30 | public IConfigurationProvider Build(IConfigurationBuilder builder) 31 | { 32 | return new ServiceFabricConfigurationProvider(this.ActivationContext, this.options); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.HttpSys/HttpSysCommunicationListener.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 6 | { 7 | using System; 8 | using System.Fabric; 9 | using System.Globalization; 10 | using Microsoft.AspNetCore.Hosting; 11 | using Microsoft.Extensions.Hosting; 12 | 13 | /// 14 | /// An AspNetCore HttpSys server based communication listener for Service Fabric stateless or stateful service. 15 | /// 16 | public class HttpSysCommunicationListener : AspNetCoreCommunicationListener 17 | { 18 | private readonly string endpointName; 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The context of the service for which this communication listener is being constructed. 24 | /// Name of endpoint resource defined in service manifest that should be used to create the address for listener. 25 | /// Delegate to build Microsoft.AspNetCore.Hosting.IWebHost, endpoint url generated by the listener is given as input to this delegate. 26 | /// This gives the flexibility to change the url before creating Microsoft.AspNetCore.Hosting.IWebHost if needed. 27 | public HttpSysCommunicationListener(ServiceContext serviceContext, string endpointName, Func build) 28 | : base(serviceContext, build) 29 | { 30 | if (string.IsNullOrEmpty(endpointName)) 31 | { 32 | throw new ArgumentException(SR.EndpointNameNullOrEmptyExceptionMessage); 33 | } 34 | 35 | this.endpointName = endpointName; 36 | } 37 | 38 | /// 39 | /// Initializes a new instance of the class. 40 | /// 41 | /// The context of the service for which this communication listener is being constructed. 42 | /// Name of endpoint resource defined in service manifest that should be used to create the address for listener. 43 | /// Delegate to build Microsoft.Extensions.Hosting.IHost, endpoint url generated by the listener is given as input to this delegate. 44 | /// This gives the flexibility to change the url before creating Microsoft.Extensions.Hosting.IHost if needed. 45 | public HttpSysCommunicationListener(ServiceContext serviceContext, string endpointName, Func build) 46 | : base(serviceContext, build) 47 | { 48 | if (string.IsNullOrEmpty(endpointName)) 49 | { 50 | throw new ArgumentException(SR.EndpointNameNullOrEmptyExceptionMessage); 51 | } 52 | 53 | this.endpointName = endpointName; 54 | } 55 | 56 | /// 57 | /// Gets url for the listener. Listener url is created using the endpointName passed in the constructor. 58 | /// 59 | /// url for the listener. 60 | protected override string GetListenerUrl() 61 | { 62 | var serviceEndpoint = this.GetEndpointResourceDescription(this.endpointName); 63 | var listenUrl = string.Format( 64 | CultureInfo.InvariantCulture, 65 | "{0}://+:{1}", 66 | serviceEndpoint.Protocol.ToString().ToLowerInvariant(), 67 | serviceEndpoint.Port); 68 | 69 | return listenUrl; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.HttpSys/Microsoft.ServiceFabric.AspNetCore.HttpSys.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Microsoft.ServiceFabric.Services.Communication.AspNetCore 7 | Microsoft.ServiceFabric.AspNetCore.HttpSys 8 | $(OutputPath)\$(AssemblyName).xml 9 | net462;net8.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | True 26 | True 27 | SR.resx 28 | 29 | 30 | 31 | 32 | ResXFileCodeGenerator 33 | SR.Designer.cs 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.HttpSys/SR.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class SR { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal SR() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.ServiceFabric.Services.Communication.AspNetCore.SR", typeof(SR).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to endpointName cannot be null or empty string.. 65 | /// 66 | internal static string EndpointNameNullOrEmptyExceptionMessage { 67 | get { 68 | return ResourceManager.GetString("EndpointNameNullOrEmptyExceptionMessage", resourceCulture); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.HttpSys/SR.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | endpointName cannot be null or empty string. 122 | 123 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Kestrel/KestrelCommunicationListener.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 6 | { 7 | using System; 8 | using System.Fabric; 9 | using System.Globalization; 10 | using Microsoft.AspNetCore.Hosting; 11 | using Microsoft.Extensions.Hosting; 12 | 13 | /// 14 | /// An AspNetCore Kestrel based communication listener for Service Fabric stateless or stateful service. 15 | /// 16 | public class KestrelCommunicationListener : AspNetCoreCommunicationListener 17 | { 18 | private readonly string endpointName; 19 | 20 | /// 21 | /// Initializes a new instance of the class using a default address with http protocol and port 0. 22 | /// Kestrel will dynamically bind to an unspecified, available port when port 0 is specified in url. 23 | /// 24 | /// The context of the service for which this communication listener is being constructed. 25 | /// Delegate to build Microsoft.AspNetCore.Hosting.IWebHost, endpoint url generated by the listener is given as input to this delegate. 26 | /// This gives the flexibility to change the url before creating Microsoft.AspNetCore.Hosting.IWebHost if needed. 27 | public KestrelCommunicationListener(ServiceContext serviceContext, Func build) 28 | : this(serviceContext, null, build) 29 | { 30 | } 31 | 32 | /// 33 | /// Initializes a new instance of the class using a default address with http protocol and port 0. 34 | /// Kestrel will dynamically bind to an unspecified, available port when port 0 is specified in url. 35 | /// 36 | /// The context of the service for which this communication listener is being constructed. 37 | /// Delegate to build Microsoft.Extensions.Hosting.IHost, endpoint url generated by the listener is given as input to this delegate. 38 | /// This gives the flexibility to change the url before creating Microsoft.Extensions.Hosting.IHost if needed. 39 | public KestrelCommunicationListener(ServiceContext serviceContext, Func build) 40 | : this(serviceContext, null, build) 41 | { 42 | } 43 | 44 | /// 45 | /// Initializes a new instance of the class. 46 | /// 47 | /// The context of the service for which this communication listener is being constructed. 48 | /// Name of endpoint resource defined in service manifest that should be used to create the address for listener. 49 | /// Protocol and port specified in this endpoint is used to create the url. 50 | /// If the endpointName is null, a default address with http protocol and port 0 will be used. 51 | /// Kestrel will dynamically bind to an unspecified, available port when port 0 is specified in url. 52 | /// If the specified endpointName is not found in service manifest, an InvalidOperationException indicating this will be thrown. 53 | /// Delegate to build Microsoft.AspNetCore.Hosting.IWebHost, endpoint url generated by the listener is given as input to this delegate. 54 | /// This gives the flexibility to change the url before creating Microsoft.AspNetCore.Hosting.IWebHost if needed. 55 | public KestrelCommunicationListener(ServiceContext serviceContext, string endpointName, Func build) 56 | : base(serviceContext, build) 57 | { 58 | if (endpointName?.Length == 0) 59 | { 60 | throw new ArgumentException(SR.EndpointNameEmptyExceptionMessage); 61 | } 62 | 63 | this.endpointName = endpointName; 64 | } 65 | 66 | /// 67 | /// Initializes a new instance of the class. 68 | /// 69 | /// The context of the service for which this communication listener is being constructed. 70 | /// Name of endpoint resource defined in service manifest that should be used to create the address for listener. 71 | /// Protocol and port specified in this endpoint is used to create the url. 72 | /// If the endpointName is null, a default address with http protocol and port 0 will be used. 73 | /// Kestrel will dynamically bind to an unspecified, available port when port 0 is specified in url. 74 | /// If the specified endpointName is not found in service manifest, an InvalidOperationException indicating this will be thrown. 75 | /// Delegate to build Microsoft.Extensions.Hosting.IHost, endpoint url generated by the listener is given as input to this delegate. 76 | /// This gives the flexibility to change the url before creating Microsoft.Extensions.Hosting.IHost if needed. 77 | public KestrelCommunicationListener(ServiceContext serviceContext, string endpointName, Func build) 78 | : base(serviceContext, build) 79 | { 80 | if (endpointName?.Length == 0) 81 | { 82 | throw new ArgumentException(SR.EndpointNameEmptyExceptionMessage); 83 | } 84 | 85 | this.endpointName = endpointName; 86 | } 87 | 88 | /// 89 | /// Gets url for the listener. Listener url is created using the endpointName passed in the constructor. 90 | /// If the endpointName was null, a default url with http protocol and port zero is returned. 91 | /// 92 | /// url for the listener. 93 | protected override string GetListenerUrl() 94 | { 95 | // url with WebServer is always registered as http://+:port. 96 | var listenUrl = "http://+:0"; 97 | 98 | // Get protocol and port from endpoint resource if specified. 99 | if (this.endpointName != null) 100 | { 101 | var serviceEndpoint = this.GetEndpointResourceDescription(this.endpointName); 102 | listenUrl = string.Format( 103 | CultureInfo.InvariantCulture, 104 | "{0}://+:{1}", 105 | serviceEndpoint.Protocol.ToString().ToLowerInvariant(), 106 | serviceEndpoint.Port); 107 | } 108 | 109 | return listenUrl; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Kestrel/Microsoft.ServiceFabric.AspNetCore.Kestrel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Microsoft.ServiceFabric.AspNetCore.Kestrel 7 | Microsoft.ServiceFabric.Services.Communication.AspNetCore 8 | $(OutputPath)\$(AssemblyName).xml 9 | net462;net8.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | True 26 | True 27 | SR.resx 28 | 29 | 30 | 31 | 32 | ResXFileCodeGenerator 33 | SR.Designer.cs 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Kestrel/SR.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class SR { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal SR() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.ServiceFabric.Services.Communication.AspNetCore.SR", typeof(SR).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to endpointResourceName cannot be empty string.. 65 | /// 66 | internal static string EndpointNameEmptyExceptionMessage { 67 | get { 68 | return ResourceManager.GetString("EndpointNameEmptyExceptionMessage", resourceCulture); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore.Kestrel/SR.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | endpointResourceName cannot be empty string. 122 | 123 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/ApplicationBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 7 | { 8 | using System; 9 | using Microsoft.AspNetCore.Builder; 10 | 11 | /// 12 | /// Class containing extension methods for IApplicationBuilder. 13 | /// 14 | public static class ApplicationBuilderExtensions 15 | { 16 | /// 17 | /// Extension method to use ServiceFabricMiddleware for Service Fabric stateful or stateless service 18 | /// using Kestrel or HttpSys as WebServer. 19 | /// 20 | /// Microsoft.AspNetCore.Builder.IApplicationBuilder. 21 | /// Url suffix to determine if the request is meant for current partition and replica. 22 | /// IApplicationBuilder instance. 23 | public static IApplicationBuilder UseServiceFabricMiddleware(this IApplicationBuilder builder, string urlSuffix) 24 | { 25 | if (builder == null) 26 | { 27 | throw new ArgumentNullException("builder"); 28 | } 29 | 30 | if (urlSuffix == null) 31 | { 32 | throw new ArgumentNullException("urlSuffix"); 33 | } 34 | 35 | return builder.UseMiddleware(urlSuffix); 36 | } 37 | 38 | /// 39 | /// Extension method to use ServiceFabricReverseProxyIntegrationMiddleware for Service Fabric stateful or stateless service 40 | /// using Kestrel or HttpSys as WebServer. 41 | /// 42 | /// Microsoft.AspNetCore.Builder.IApplicationBuilder. 43 | /// IApplicationBuilder instance. 44 | public static IApplicationBuilder UseServiceFabricReverseProxyIntegrationMiddleware(this IApplicationBuilder builder) 45 | { 46 | if (builder == null) 47 | { 48 | throw new ArgumentNullException(nameof(builder)); 49 | } 50 | 51 | return builder.UseMiddleware(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/AspNetCoreCommunicationListener.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 7 | { 8 | using System; 9 | using System.Fabric; 10 | using System.Fabric.Description; 11 | using System.Globalization; 12 | using System.Linq; 13 | using System.Threading; 14 | using System.Threading.Tasks; 15 | using Microsoft.AspNetCore.Hosting; 16 | using Microsoft.AspNetCore.Hosting.Server; 17 | using Microsoft.AspNetCore.Hosting.Server.Features; 18 | using Microsoft.Extensions.DependencyInjection; 19 | using Microsoft.Extensions.Hosting; 20 | using Microsoft.ServiceFabric.Services.Communication.Runtime; 21 | 22 | /// 23 | /// Base class for creating AspNetCore based communication listener for Service Fabric stateless or stateful service. 24 | /// 25 | public abstract class AspNetCoreCommunicationListener : ICommunicationListener 26 | { 27 | private readonly ServiceContext serviceContext; 28 | private readonly ICommunicationListener internalListener; 29 | private string urlSuffix = null; 30 | private bool configuredToUseUniqueServiceUrl = false; 31 | 32 | /// 33 | /// Initializes a new instance of the class. 34 | /// 35 | /// The context of the service for which this communication listener is being constructed. 36 | /// Delegate to build Microsoft.AspNetCore.Hosting.IWebHost, endpoint url generated by the listener is given as input to this delegate. 37 | /// This gives the flexibility to change the url before creating Microsoft.AspNetCore.Hosting.IWebHost if needed. 38 | public AspNetCoreCommunicationListener(ServiceContext serviceContext, Func build) 39 | { 40 | if (serviceContext == null) 41 | { 42 | throw new ArgumentNullException("serviceContext"); 43 | } 44 | 45 | if (build == null) 46 | { 47 | throw new ArgumentNullException("build"); 48 | } 49 | 50 | this.serviceContext = serviceContext; 51 | this.internalListener = new WebHostCommunicationListener(build, this); 52 | this.urlSuffix = string.Empty; 53 | } 54 | 55 | /// 56 | /// Initializes a new instance of the class. 57 | /// 58 | /// The context of the service for which this communication listener is being constructed. 59 | /// Delegate to build Microsoft.Extensions.Hosting.IHost, endpoint url generated by the listener is given as input to this delegate. 60 | /// This gives the flexibility to change the url before creating Microsoft.Extensions.Hosting.IHost if needed. 61 | public AspNetCoreCommunicationListener(ServiceContext serviceContext, Func build) 62 | { 63 | if (serviceContext == null) 64 | { 65 | throw new ArgumentNullException("serviceContext"); 66 | } 67 | 68 | if (build == null) 69 | { 70 | throw new ArgumentNullException("build"); 71 | } 72 | 73 | this.serviceContext = serviceContext; 74 | this.internalListener = new GenericHostCommunicationListener(build, this); 75 | this.urlSuffix = string.Empty; 76 | } 77 | 78 | /// 79 | /// Gets the context of the service for which this communication listener is being constructed. 80 | /// 81 | public ServiceContext ServiceContext 82 | { 83 | get { return this.serviceContext; } 84 | } 85 | 86 | /// 87 | /// Gets the url suffix to be used based on specified in 88 | /// . 89 | /// 90 | public string UrlSuffix 91 | { 92 | get 93 | { 94 | return this.urlSuffix; 95 | } 96 | } 97 | 98 | /// 99 | /// This method causes the communication listener to close. Close is a terminal state and 100 | /// this method causes the transition to close ungracefully. Any outstanding operations 101 | /// (including close) should be canceled when this method is called. 102 | /// 103 | public virtual void Abort() 104 | { 105 | this.internalListener.Abort(); 106 | } 107 | 108 | /// 109 | /// This method causes the communication listener to close. Close is a terminal state and 110 | /// this method allows the communication listener to transition to this state in a graceful manner. 111 | /// 112 | /// Cancellation token. 113 | /// 114 | /// A Task that represents outstanding operation. 115 | /// 116 | public virtual Task CloseAsync(CancellationToken cancellationToken) 117 | { 118 | return this.internalListener.CloseAsync(cancellationToken); 119 | } 120 | 121 | /// 122 | /// This method causes the communication listener to be opened. Once the Open 123 | /// completes, the communication listener becomes usable - accepts and sends messages. 124 | /// 125 | /// Cancellation token. 126 | /// 127 | /// A Task that represents outstanding operation. The result of the Task is 128 | /// is endpoint string on which IWebHost/IHost is listening. 129 | /// 130 | public virtual Task OpenAsync(CancellationToken cancellationToken) 131 | { 132 | return this.internalListener.OpenAsync(cancellationToken); 133 | } 134 | 135 | /// 136 | /// Configures the listener to use UniqueServiceUrl by appending a urlSuffix PartitionId and ReplicaId. 137 | /// It helps in scenarios when ServiceA listening on a node on port X moves and another Service takes its place on the same node and starts using the same port X, 138 | /// The UniqueServiceUrl in conjunction with middleware rejects requests meant for serviceA arriving at ServiceB. 139 | /// Example: 140 | /// Service A is dynamically assigned port 30000 on node with IP 10.0.0.1, it listens on http://+:30000/ and reports to Naming service http://10.0.0.1:30000/serviceName-A/partitionId-A/replicaId-A 141 | /// Client resolves URL from NS: http://10.0.0.1:30000/serviceName-A/partitionId-A/replicaId-A and sends a request, Service A compares URL path segments to its own service name, partition ID, replica ID, finds they are equal, serves request. 142 | /// Now Service A moves to a different node and Service B comes up at the node with IP 10.0.0.1 and is dynamically assigned port 30000. 143 | /// Service B listens on: http://+:30000/ and reports to NS http://10.0.0.1:30000/serviceName-B/partitionId-B/replicaId-B, Client for Service a sends request to http://10.0.0.1:30000/serviceName-A/partitionId-A/replicaId-A 144 | /// Service B compares URL path segments to its own service name, partition ID, replica ID, finds they do not match, ends the request and responds with HTTP 410. Client receives 410 and re-resolves for service A. 145 | /// 146 | internal void ConfigureToUseUniqueServiceUrl() 147 | { 148 | if (!this.configuredToUseUniqueServiceUrl) 149 | { 150 | this.urlSuffix = string.Format(CultureInfo.InvariantCulture, "/{0}/{1}", this.serviceContext.PartitionId, this.serviceContext.ReplicaOrInstanceId); 151 | 152 | if (this.ServiceContext is StatefulServiceContext) 153 | { 154 | // For stateful service, also append a Guid, Guid makes the url unique in scenarios for stateful services when Listener is 155 | // created to support read on secondary and change role happens from Primary->Secondary for the replica. 156 | this.urlSuffix += "/" + Guid.NewGuid(); 157 | } 158 | 159 | this.configuredToUseUniqueServiceUrl = true; 160 | } 161 | } 162 | 163 | /// 164 | /// Gets url for this listener to be used with Web Server. 165 | /// 166 | /// url for this listener to be used with Web Server. 167 | protected internal abstract string GetListenerUrl(); 168 | 169 | /// 170 | /// Retrieves the endpoint resource with a given name from the service manifest. 171 | /// 172 | /// The name of the endpoint. 173 | /// The endpoint resource with the specified name. 174 | protected EndpointResourceDescription GetEndpointResourceDescription(string endpointName) 175 | { 176 | if (endpointName == null) 177 | { 178 | throw new ArgumentNullException("endpointName"); 179 | } 180 | 181 | if (!this.serviceContext.CodePackageActivationContext.GetEndpoints().Contains(endpointName)) 182 | { 183 | throw new InvalidOperationException(string.Format(SR.EndpointNameNotFoundExceptionMessage, endpointName)); 184 | } 185 | 186 | return this.serviceContext.CodePackageActivationContext.GetEndpoint(endpointName); 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/Friend.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | using System.Runtime.CompilerServices; 6 | 7 | [assembly: InternalsVisibleTo("Microsoft.ServiceFabric.AspNetCore.Tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")] 8 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/GenericHostCommunicationListener.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 6 | { 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Fabric; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading; 13 | using System.Threading.Tasks; 14 | using Microsoft.AspNetCore.Hosting.Server; 15 | using Microsoft.AspNetCore.Hosting.Server.Features; 16 | using Microsoft.Extensions.DependencyInjection; 17 | using Microsoft.Extensions.Hosting; 18 | using Microsoft.ServiceFabric.Services.Communication.Runtime; 19 | 20 | internal class GenericHostCommunicationListener : ICommunicationListener 21 | { 22 | private readonly Func build; 23 | private readonly ServiceContext serviceContext; 24 | private readonly AspNetCoreCommunicationListener listener; 25 | private IHost host; 26 | 27 | public GenericHostCommunicationListener(Func build, AspNetCoreCommunicationListener listener) 28 | { 29 | this.serviceContext = listener.ServiceContext; 30 | this.build = build; 31 | this.listener = listener; 32 | } 33 | 34 | public void Abort() 35 | { 36 | if (this.host != null) 37 | { 38 | this.host.Dispose(); 39 | } 40 | } 41 | 42 | public async Task CloseAsync(CancellationToken cancellationToken) 43 | { 44 | if (this.host != null) 45 | { 46 | await this.host.StopAsync(cancellationToken); 47 | this.host.Dispose(); 48 | } 49 | } 50 | 51 | public async Task OpenAsync(CancellationToken cancellationToken) 52 | { 53 | this.host = this.build(this.listener.GetListenerUrl(), this.listener); 54 | if (this.host == null) 55 | { 56 | throw new InvalidOperationException(SR.HostNullExceptionMessage); 57 | } 58 | 59 | await this.host.StartAsync(cancellationToken); 60 | 61 | var server = this.host.Services.GetService(); 62 | if (server == null) 63 | { 64 | throw new InvalidOperationException(SR.WebServerNotFound); 65 | } 66 | 67 | var url = server.Features.Get().Addresses.FirstOrDefault(); 68 | if (url == null) 69 | { 70 | throw new InvalidOperationException(SR.ErrorNoUrlFromAspNetCore); 71 | } 72 | 73 | var publishAddress = this.serviceContext.PublishAddress; 74 | 75 | if (url.Contains("://+:")) 76 | { 77 | url = url.Replace("://+:", $"://{publishAddress}:"); 78 | } 79 | else if (url.Contains("://[::]:")) 80 | { 81 | url = url.Replace("://[::]:", $"://{publishAddress}:"); 82 | } 83 | 84 | // When returning url to naming service, add UrlSuffix to it. 85 | // This UrlSuffix will be used by middleware to: 86 | // - drop calls not intended for the service and return 410. 87 | // - modify Path and PathBase in Microsoft.AspNetCore.Http.HttpRequest to be sent correctly to the service code. 88 | url = url.TrimEnd(new[] { '/' }) + this.listener.UrlSuffix; 89 | 90 | return url; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/Microsoft.ServiceFabric.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Microsoft.ServiceFabric.AspNetCore 7 | Microsoft.ServiceFabric.Services.Communication.AspNetCore 8 | $(OutputPath)\$(AssemblyName).xml 9 | net462;net8.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | True 23 | True 24 | SR.resx 25 | 26 | 27 | 28 | 29 | ResXFileCodeGenerator 30 | SR.Designer.cs 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/PathStringExtensions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 7 | { 8 | using System; 9 | using System.Threading.Tasks; 10 | using Microsoft.AspNetCore.Builder; 11 | using Microsoft.AspNetCore.Http; 12 | 13 | /// 14 | /// PathString extension as aspnet core 1.0.0 binaries doesn't have StartsWithSegments() method with an out param for matched string. 15 | /// 16 | internal static class PathStringExtensions 17 | { 18 | internal static bool StartsWithSegments( 19 | this PathString pathString, 20 | PathString other, 21 | out PathString matched, 22 | out PathString remaining) 23 | { 24 | var value1 = pathString.Value ?? string.Empty; 25 | var value2 = other.Value ?? string.Empty; 26 | 27 | if (value1.StartsWith(value2, StringComparison.OrdinalIgnoreCase)) 28 | { 29 | if (value1.Length == value2.Length || value1[value2.Length] == '/') 30 | { 31 | matched = new PathString(value1.Substring(0, value2.Length)); 32 | remaining = new PathString(value1.Substring(value2.Length)); 33 | return true; 34 | } 35 | } 36 | 37 | remaining = PathString.Empty; 38 | matched = PathString.Empty; 39 | return false; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/SR.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class SR { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal SR() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.ServiceFabric.Services.Communication.AspNetCore.SR", typeof(SR).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to {0} not found in Service Manifest.. 65 | /// 66 | internal static string EndpointNameNotFoundExceptionMessage { 67 | get { 68 | return ResourceManager.GetString("EndpointNameNotFoundExceptionMessage", resourceCulture); 69 | } 70 | } 71 | 72 | /// 73 | /// Looks up a localized string similar to "No Url returned from AspNetCore IServerAddressesFeature.. 74 | /// 75 | internal static string ErrorNoUrlFromAspNetCore { 76 | get { 77 | return ResourceManager.GetString("ErrorNoUrlFromAspNetCore", resourceCulture); 78 | } 79 | } 80 | 81 | /// 82 | /// Looks up a localized string similar to IHost returned from build delegate is null.. 83 | /// 84 | internal static string HostNullExceptionMessage { 85 | get { 86 | return ResourceManager.GetString("HostNullExceptionMessage", resourceCulture); 87 | } 88 | } 89 | 90 | /// 91 | /// Looks up a localized string similar to IWebHost returned from build delegate is null.. 92 | /// 93 | internal static string WebHostNullExceptionMessage { 94 | get { 95 | return ResourceManager.GetString("WebHostNullExceptionMessage", resourceCulture); 96 | } 97 | } 98 | 99 | /// 100 | /// Looks up a localized string similar to No web server found over IHost. 101 | /// 102 | internal static string WebServerNotFound { 103 | get { 104 | return ResourceManager.GetString("WebServerNotFound", resourceCulture); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/SR.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | {0} not found in Service Manifest. 122 | 123 | 124 | "No Url returned from AspNetCore IServerAddressesFeature. 125 | 126 | 127 | IHost returned from build delegate is null. 128 | 129 | 130 | IWebHost returned from build delegate is null. 131 | 132 | 133 | No web server found over IHost 134 | 135 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/ServiceFabricIntegrationOptions.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 6 | { 7 | using System; 8 | 9 | /// 10 | /// Integration options for method when used with Microsoft.AspNetCore.Hosting.IWebHostBuilder. 11 | /// 12 | [Flags] 13 | public enum ServiceFabricIntegrationOptions 14 | { 15 | /// 16 | /// This option will not configure the to add any suffix to url when providing the url to Service Fabric Runtime from its method. 17 | /// 18 | None = 0x00, 19 | 20 | /// 21 | /// This option will configure the to add a url suffix containing and 22 | /// to url when providing the url to Service Fabric Runtime from its method. 23 | /// 24 | UseUniqueServiceUrl = 0x01, 25 | 26 | /// 27 | /// This option will enable the Service Fabric Reverse Proxy integration middleware. 28 | /// 29 | UseReverseProxyIntegration = 0x02, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/ServiceFabricMiddleware.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 7 | { 8 | using System; 9 | using System.Threading.Tasks; 10 | using Microsoft.AspNetCore.Http; 11 | 12 | /// 13 | /// A middleware to be used with Service Fabric stateful and stateless services hosted in Kestrel or HttpSys. 14 | /// This middleware examines the Microsoft.AspNetCore.Http.HttpRequest.Path in request to determine if the request is intended for this replica. 15 | /// 16 | /// 17 | /// This middleware when used with Kestrel and HttpSys based Service Fabric Communication Listeners allows handling of scenarios when 18 | /// the Replica1 listening on Node1 and por11 has moved and another Replica2 is opened on Node1 got Port1. 19 | /// A client which has resolved Replica1 before it moved, will send the request to Node1:Port1. Using this middleware 20 | /// Replica2 can reject calls which were meant for Replica1 by examining the Path in incoming request. 21 | /// 22 | public class ServiceFabricMiddleware 23 | { 24 | private readonly RequestDelegate next; 25 | private readonly string urlSuffix; 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// Next request handler in pipeline. 31 | /// Url suffix to determine if the request is meant for current partition and replica. 32 | public ServiceFabricMiddleware(RequestDelegate next, string urlSuffix) 33 | { 34 | if (next == null) 35 | { 36 | throw new ArgumentNullException("next"); 37 | } 38 | 39 | if (urlSuffix == null) 40 | { 41 | throw new ArgumentNullException("urlSuffix"); 42 | } 43 | 44 | this.urlSuffix = urlSuffix; 45 | this.next = next; 46 | } 47 | 48 | /// 49 | /// Invoke. 50 | /// 51 | /// Context. 52 | /// Task for the execution by next middleware in pipeline. 53 | public async Task Invoke(HttpContext context) 54 | { 55 | if (context == null) 56 | { 57 | throw new ArgumentNullException("context"); 58 | } 59 | 60 | if (this.urlSuffix.Length == 0) 61 | { 62 | // when urlSuffix is empty string, just call the next middleware in pipeline. 63 | await this.next(context); 64 | } 65 | else 66 | { 67 | // If this middleware is enabled by specifying UseServiceFabricIntegration(), CommunicationListnerBehavior is: 68 | // With ServiceFabricIntegrationOptions.UseUniqueServiceUrl (urlSuffix is /PartitionId/ReplicaOrInstanceId) 69 | // - Url given to WebServer is http://+:port 70 | // - Url given to Service Fabric Runtime is http://ip:port/PartitionId/ReplicaOrInstanceId 71 | 72 | // Since when registering with IWebHost, only http://+:port is provided: 73 | // - HttpRequest.Path contains everything in url after http://+:port, and it must start with urlSuffix 74 | 75 | // So short circuit and return StatusCode 410 if (message isn't intended for this replica,): 76 | // - HttpRequest.Path doesn't start with urlSuffix 77 | if (!context.Request.Path.StartsWithSegments(this.urlSuffix, out var matchedPath, out var remainingPath)) 78 | { 79 | context.Response.StatusCode = StatusCodes.Status410Gone; 80 | return; 81 | } 82 | 83 | // All good, change Path, PathBase and call next middleware in the pipeline 84 | var originalPath = context.Request.Path; 85 | var originalPathBase = context.Request.PathBase; 86 | context.Request.Path = remainingPath; 87 | context.Request.PathBase = originalPathBase.Add(matchedPath); 88 | 89 | try 90 | { 91 | await this.next(context); 92 | } 93 | finally 94 | { 95 | context.Request.Path = originalPath; 96 | context.Request.PathBase = originalPathBase; 97 | } 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/ServiceFabricReverseProxyIntegrationMiddleware.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 6 | { 7 | using System; 8 | using System.Threading.Tasks; 9 | using Microsoft.AspNetCore.Http; 10 | 11 | /// 12 | /// A middleware to be used with Service Fabric stateful and stateless services hosted in Kestrel or HttpSys. 13 | /// This middleware automatically adds X-ServiceFabric ResourceNotFound header, required by the Service Fabric Reverse Proxy, when 404 status code is returned. 14 | /// 15 | public class ServiceFabricReverseProxyIntegrationMiddleware 16 | { 17 | private const string XServiceFabricHeader = "X-ServiceFabric"; 18 | private const string XServiceFabricResourceNotFoundValue = "ResourceNotFound"; 19 | 20 | private readonly RequestDelegate next; 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// Next request handler in pipeline. 26 | public ServiceFabricReverseProxyIntegrationMiddleware(RequestDelegate next) 27 | { 28 | if (next == null) 29 | { 30 | throw new ArgumentNullException(nameof(next)); 31 | } 32 | 33 | this.next = next; 34 | } 35 | 36 | /// 37 | /// Invoke. 38 | /// 39 | /// Context. 40 | /// Task for the execution by next middleware in pipeline. 41 | public Task Invoke(HttpContext context) 42 | { 43 | if (context == null) 44 | { 45 | throw new ArgumentNullException(nameof(context)); 46 | } 47 | 48 | context.Response.OnStarting( 49 | state => 50 | { 51 | var response = (HttpResponse)state; 52 | if (response.StatusCode == StatusCodes.Status404NotFound) 53 | { 54 | response.Headers[XServiceFabricHeader] = XServiceFabricResourceNotFoundValue; 55 | } 56 | 57 | return Task.CompletedTask; 58 | }, 59 | context.Response); 60 | 61 | return this.next(context); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/ServiceFabricSetupFilter.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 6 | { 7 | using System; 8 | using Microsoft.AspNetCore.Builder; 9 | using Microsoft.AspNetCore.Hosting; 10 | 11 | internal class ServiceFabricSetupFilter : IStartupFilter 12 | { 13 | private readonly string urlSuffix; 14 | private readonly ServiceFabricIntegrationOptions options; 15 | 16 | internal ServiceFabricSetupFilter(string urlSuffix, ServiceFabricIntegrationOptions options) 17 | { 18 | this.urlSuffix = urlSuffix; 19 | this.options = options; 20 | } 21 | 22 | public Action Configure(Action next) 23 | { 24 | return app => 25 | { 26 | if (!string.IsNullOrEmpty(this.urlSuffix)) 27 | { 28 | app.UseServiceFabricMiddleware(this.urlSuffix); 29 | } 30 | 31 | if (this.options.HasFlag(ServiceFabricIntegrationOptions.UseReverseProxyIntegration)) 32 | { 33 | app.UseServiceFabricReverseProxyIntegrationMiddleware(); 34 | } 35 | 36 | next(app); 37 | }; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/WebHostBuilderServiceFabricExtension.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 6 | { 7 | using System; 8 | using Microsoft.AspNetCore.Hosting; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | /// 12 | /// Class containing Service Fabric related extension methods for Microsoft.AspNetCore.Hosting.IWebHostBuilder. 13 | /// 14 | public static class WebHostBuilderServiceFabricExtension 15 | { 16 | private static readonly string SettingName = "UseServiceFabricIntegration"; 17 | 18 | /// 19 | /// Configures the Service to use ServiceFabricMiddleware and tells the listener that middleware is configured for the service so that it can 20 | /// suffix PartitionId and ReplicaOrInstanceId to url before providing it to Service Fabric Runtime. 21 | /// 22 | /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure. 23 | /// The to configure. 24 | /// Options to configure ServiceFabricMiddleware and AspNetCoreCommunicationListener. 25 | /// The Microsoft.AspNetCore.Hosting.IWebHostBuilder. 26 | public static IWebHostBuilder UseServiceFabricIntegration(this IWebHostBuilder hostBuilder, AspNetCoreCommunicationListener listener, ServiceFabricIntegrationOptions options) 27 | { 28 | if (hostBuilder == null) 29 | { 30 | throw new ArgumentNullException("hostBuilder"); 31 | } 32 | 33 | // Check if 'UseServiceFabricIntegration' has already been called. 34 | if (hostBuilder.GetSetting(SettingName) == true.ToString()) 35 | { 36 | return hostBuilder; 37 | } 38 | 39 | // Set flag to prevent double service configuration 40 | hostBuilder.UseSetting(SettingName, true.ToString()); 41 | 42 | // Configure listener to use PartitionId and ReplicaId as urlSuffix only when specified in options. 43 | if (options.HasFlag(ServiceFabricIntegrationOptions.UseUniqueServiceUrl)) 44 | { 45 | // notify listener to use urlSuffix when giving url to Service Fabric Runtime from OpenAsync() 46 | listener.ConfigureToUseUniqueServiceUrl(); 47 | } 48 | 49 | hostBuilder.ConfigureServices(services => 50 | { 51 | // Configure MiddleWare 52 | services.AddSingleton(new ServiceFabricSetupFilter(listener.UrlSuffix, options)); 53 | }); 54 | 55 | return hostBuilder; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Microsoft.ServiceFabric.AspNetCore/WebHostCommunicationListener.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | namespace Microsoft.ServiceFabric.Services.Communication.AspNetCore 6 | { 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Fabric; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading; 13 | using System.Threading.Tasks; 14 | using Microsoft.AspNetCore.Hosting; 15 | using Microsoft.AspNetCore.Hosting.Server.Features; 16 | using Microsoft.ServiceFabric.Services.Communication.Runtime; 17 | 18 | internal class WebHostCommunicationListener : ICommunicationListener 19 | { 20 | private readonly Func build; 21 | private readonly ServiceContext serviceContext; 22 | private readonly AspNetCoreCommunicationListener listener; 23 | private IWebHost host; 24 | 25 | public WebHostCommunicationListener(Func build, AspNetCoreCommunicationListener listener) 26 | { 27 | this.serviceContext = listener.ServiceContext; 28 | this.build = build; 29 | this.listener = listener; 30 | } 31 | 32 | public void Abort() 33 | { 34 | if (this.host != null) 35 | { 36 | this.host.Dispose(); 37 | } 38 | } 39 | 40 | public async Task CloseAsync(CancellationToken cancellationToken) 41 | { 42 | if (this.host != null) 43 | { 44 | await this.host.StopAsync(cancellationToken); 45 | this.host.Dispose(); 46 | } 47 | } 48 | 49 | public async Task OpenAsync(CancellationToken cancellationToken) 50 | { 51 | this.host = this.build(this.listener.GetListenerUrl(), this.listener); 52 | if (this.host == null) 53 | { 54 | throw new InvalidOperationException(SR.WebHostNullExceptionMessage); 55 | } 56 | 57 | await this.host.StartAsync(cancellationToken); 58 | 59 | var url = this.host.ServerFeatures.Get().Addresses.FirstOrDefault(); 60 | 61 | if (url == null) 62 | { 63 | throw new InvalidOperationException(SR.ErrorNoUrlFromAspNetCore); 64 | } 65 | 66 | var publishAddress = this.serviceContext.PublishAddress; 67 | 68 | if (url.Contains("://+:")) 69 | { 70 | url = url.Replace("://+:", $"://{publishAddress}:"); 71 | } 72 | else if (url.Contains("://[::]:")) 73 | { 74 | url = url.Replace("://[::]:", $"://{publishAddress}:"); 75 | } 76 | 77 | // When returning url to naming service, add UrlSuffix to it. 78 | // This UrlSuffix will be used by middleware to: 79 | // - drop calls not intended for the service and return 410. 80 | // - modify Path and PathBase in Microsoft.AspNetCore.Http.HttpRequest to be sent correctly to the service code. 81 | url = url.TrimEnd(new[] { '/' }) + this.listener.UrlSuffix; 82 | 83 | return url; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/AspNetCoreCommunicationListenerTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Fabric.Description; 11 | using System.Threading; 12 | using FluentAssertions; 13 | using Microsoft.AspNetCore.Hosting; 14 | using Microsoft.AspNetCore.Hosting.Server; 15 | using Microsoft.AspNetCore.Hosting.Server.Features; 16 | using Microsoft.AspNetCore.Http.Features; 17 | using Microsoft.Extensions.DependencyInjection; 18 | using Microsoft.Extensions.Hosting; 19 | using Microsoft.ServiceFabric.Services.Communication.AspNetCore; 20 | using Moq; 21 | 22 | /// 23 | /// Test class for AspNetCoreCommunicationListener. 24 | /// 25 | public class AspNetCoreCommunicationListenerTests 26 | { 27 | /// 28 | /// Endpoint name used by tests. 29 | /// 30 | protected const string EndpointName = "MockEndpoint"; 31 | 32 | private const EndpointProtocol ExpectedProtocolFromEndpoint = EndpointProtocol.Http; 33 | private const string DefaultExpectedProtocol = "http"; 34 | private const string DefaultPathPrefix = "PathPrefix"; 35 | private const int DefaultExpectedPort = 0; 36 | private string urlFromListenerToBuildFunc; 37 | 38 | /// 39 | /// Gets strings for the two Host Types - WebHost and GenericHost. 40 | /// 41 | public static IEnumerable HostTypes 42 | { 43 | get 44 | { 45 | return new List 46 | { 47 | new object[] { "WebHost" }, 48 | new object[] { "GenericHost" }, 49 | }; 50 | } 51 | } 52 | 53 | /// 54 | /// Gets or sets a value indicating whether WebHost/GenericHost was started/stopped. 55 | /// 56 | protected bool IsStarted { get; set; } 57 | 58 | /// 59 | /// Gets or sets the listener used by the test. 60 | /// 61 | protected AspNetCoreCommunicationListener Listener { get; set; } 62 | 63 | /// 64 | /// Gets or sets the ServiceFabricIntegrationOption. 65 | /// 66 | protected ServiceFabricIntegrationOptions IntegrationOptions { get; set; } 67 | 68 | /// 69 | /// Gets the EndpointResourceDescription used by the test. 70 | /// 71 | /// EndpointResourceDescription isntance. 72 | protected EndpointResourceDescription GetTestEndpoint() 73 | { 74 | return new EndpointResourceDescription() 75 | { 76 | Name = EndpointName, 77 | Protocol = ExpectedProtocolFromEndpoint, 78 | 79 | // Port = ExpectedPortFromEndpoint 80 | }; 81 | } 82 | 83 | /// 84 | /// Method to build Microsoft.AspNetCore.Hosting.IWebHost. 85 | /// 86 | /// Endpoint url generated by the listener. 87 | /// Listener instance. 88 | /// IWebHost which will be used by Communication Listener. 89 | protected IWebHost IWebHostBuildFunc(string url, AspNetCoreCommunicationListener listener) 90 | { 91 | this.urlFromListenerToBuildFunc = url; 92 | 93 | // Create mock IServerAddressesFeature and set required things used by tests. 94 | var mockServerAddressFeature = new Mock(); 95 | mockServerAddressFeature.Setup(y => y.Addresses).Returns(new string[] { url }); 96 | var featureCollection = new FeatureCollection(); 97 | featureCollection.Set(mockServerAddressFeature.Object); 98 | 99 | // Create mock IWebHost and set required things used by tests. 100 | var mockWebHost = new Mock(); 101 | mockWebHost.Setup(y => y.ServerFeatures).Returns(featureCollection); 102 | 103 | // setup call backs for Start , Dispose. 104 | mockWebHost.Setup(y => y.StartAsync(CancellationToken.None)).Callback(() => this.IsStarted = true); 105 | mockWebHost.Setup(y => y.Dispose()).Callback(() => this.IsStarted = false); 106 | 107 | // tell listener whether to generate UniqueServiceUrls 108 | if (this.IntegrationOptions.Equals(ServiceFabricIntegrationOptions.UseUniqueServiceUrl)) 109 | { 110 | listener.ConfigureToUseUniqueServiceUrl(); 111 | } 112 | 113 | return mockWebHost.Object; 114 | } 115 | 116 | /// 117 | /// Method to build Microsoft.Extensions.Hosting.IHost. 118 | /// 119 | /// Endpoint url generated by the listener. 120 | /// Listener instance. 121 | /// IHost which will be used by Communication Listener. 122 | protected IHost IHostBuildFunc(string url, AspNetCoreCommunicationListener listener) 123 | { 124 | this.urlFromListenerToBuildFunc = url; 125 | 126 | // Create mock IServerAddressesFeature and set required things used by tests. 127 | var mockServerAddressFeature = new Mock(); 128 | mockServerAddressFeature.Setup(y => y.Addresses).Returns(new string[] { url }); 129 | var featureCollection = new FeatureCollection(); 130 | featureCollection.Set(mockServerAddressFeature.Object); 131 | 132 | // Create mock IServer and set required things used by tests. 133 | var mockServer = new Mock(); 134 | mockServer.Setup(y => y.Features).Returns(featureCollection); 135 | 136 | // Create ServiceCollection and IServiceProvider and set required things used for tests. 137 | var serviceCollection = new ServiceCollection(); 138 | serviceCollection.AddSingleton(mockServer.Object); 139 | var serviceProvider = serviceCollection.BuildServiceProvider(); 140 | 141 | // Create mock IHost and set required things used by tests. 142 | var mockHost = new Mock(); 143 | mockHost.Setup(y => y.Services).Returns(serviceProvider); 144 | 145 | // setup call backs for Start , Dispose. 146 | mockHost.Setup(y => y.StartAsync(CancellationToken.None)).Callback(() => this.IsStarted = true); 147 | mockHost.Setup(y => y.StopAsync(CancellationToken.None)).Callback(() => this.IsStarted = false); 148 | mockHost.Setup(y => y.Dispose()).Callback(() => this.IsStarted = false); 149 | 150 | // tell listener whether to generate UniqueServiceUrls 151 | if (this.IntegrationOptions.Equals(ServiceFabricIntegrationOptions.UseUniqueServiceUrl)) 152 | { 153 | listener.ConfigureToUseUniqueServiceUrl(); 154 | } 155 | 156 | return mockHost.Object; 157 | } 158 | 159 | /// 160 | /// Tests Url for ServiceFabricIntegrationOptions.UseUniqueServiceUrl 161 | /// 1. When endpoint name is provided (protocol and port comes from endpoint.) : 162 | /// a. url given to Func to create IWebHost/IHost should be protocol://+:port. 163 | /// b. url returned from OpenAsync should be protocol://IPAddressOrFQDN:port/PartitionId/ReplicaId. 164 | /// 165 | /// 166 | protected void UseUniqueServiceUrlOptionVerifier() 167 | { 168 | this.IntegrationOptions = ServiceFabricIntegrationOptions.UseUniqueServiceUrl; 169 | var expectedProtocol = ExpectedProtocolFromEndpoint.ToString().ToLowerInvariant(); 170 | var expectedPort = DefaultExpectedPort; 171 | 172 | Console.WriteLine("Starting Verification of urls with UseUniqueServiceUrl option when endpoint ref is provided"); 173 | var context = this.Listener.ServiceContext; 174 | var expectedUrlToBuildFunc = string.Format("{0}://+:{1}", expectedProtocol, expectedPort); 175 | var expectedUrlFromOpen = string.Format("{0}://{1}:{2}/{3}/{4}", expectedProtocol, context.NodeContext.IPAddressOrFQDN, expectedPort, context.PartitionId, context.ReplicaOrInstanceId); 176 | var actualUrlFromOpen = this.Listener.OpenAsync(CancellationToken.None).GetAwaiter().GetResult(); 177 | 178 | this.urlFromListenerToBuildFunc.Should().Be(expectedUrlToBuildFunc, "listener generates the url."); 179 | actualUrlFromOpen.Should().Be(actualUrlFromOpen, "url from OpenAsync with endpoint ref"); 180 | Console.WriteLine("Completed Verification of urls with endpoint ref"); 181 | } 182 | 183 | /// 184 | /// Tests Url for ServiceFabricIntegrationOptions.None 185 | /// 1. When endpoint name is provided (protocol and port comes from endpoint.) : 186 | /// a. url given to Func to create IWebHost/IHost should be protocol://+:port. 187 | /// b. url returned from OpenAsync should be protocol://IPAddressOrFQDN:port. 188 | /// 189 | /// 190 | protected void WithoutUseUniqueServiceUrlOptionVerifier() 191 | { 192 | this.IntegrationOptions = ServiceFabricIntegrationOptions.None; 193 | var expectedProtocol = ExpectedProtocolFromEndpoint.ToString().ToLowerInvariant(); 194 | var expectedPort = DefaultExpectedPort; 195 | 196 | Console.WriteLine("Starting Verification of urls with UseUniqueServiceUrl option when endpoint ref is provided"); 197 | var context = this.Listener.ServiceContext; 198 | var expectedUrlToBuildFunc = string.Format("{0}://+:{1}", expectedProtocol, expectedPort); 199 | var expectedUrlFromOpen = string.Format("{0}://{1}:{2}", expectedProtocol, context.NodeContext.IPAddressOrFQDN, expectedPort); 200 | var actualUrlFromOpen = this.Listener.OpenAsync(CancellationToken.None).GetAwaiter().GetResult(); 201 | 202 | this.urlFromListenerToBuildFunc.Should().Be(expectedUrlToBuildFunc, "url to Build Func is generated by listener"); 203 | actualUrlFromOpen.Should().Be(expectedUrlFromOpen, "url from OpenAsync with endpoint ref"); 204 | Console.WriteLine("Completed Verification of urls with endpoint ref"); 205 | } 206 | 207 | /// 208 | /// Verify Listener Open and Close. 209 | /// 210 | protected void ListenerOpenCloseVerifier() 211 | { 212 | // Open Close 213 | this.Listener.OpenAsync(CancellationToken.None).GetAwaiter().GetResult(); 214 | this.IsStarted.Should().BeTrue(); 215 | 216 | this.Listener.CloseAsync(CancellationToken.None).GetAwaiter().GetResult(); 217 | this.IsStarted.Should().BeFalse(); 218 | 219 | // Open Abort 220 | this.Listener.OpenAsync(CancellationToken.None).GetAwaiter().GetResult(); 221 | this.IsStarted.Should().BeTrue(); 222 | 223 | this.Listener.Abort(); 224 | this.IsStarted.Should().BeFalse(); 225 | } 226 | 227 | /// 228 | /// InvalidOperationException is thrown when Endpoint is not found in service manifest. 229 | /// 230 | protected void ExceptionForEndpointNotFoundVerifier() 231 | { 232 | Action action = () => this.Listener.OpenAsync(CancellationToken.None).GetAwaiter().GetResult(); 233 | action.Should().Throw(); 234 | } 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/HttpSysCommunicationListenerTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Fabric; 10 | using FluentAssertions; 11 | using Microsoft.ServiceFabric.Services.Communication.AspNetCore; 12 | using Xunit; 13 | 14 | /// 15 | /// Test class for HttpSysCommunicationListener. 16 | /// 17 | public class HttpSysCommunicationListenerTests : AspNetCoreCommunicationListenerTests 18 | { 19 | /// 20 | /// Tests Url for ServiceFabricIntegrationOptions.UseUniqueServiceUrl 21 | /// 1. When no endpointRef is provided: 22 | /// a. url given to Func to create IWebHost/IHost should be http://+:0 23 | /// b. url returned from OpenAsync should be http://IPAddressOrFQDN:0/PartitionId/ReplicaId 24 | /// 25 | /// 26 | /// 2. When endpointRef is provided (protocol and port comes from endpoint.) : 27 | /// a. url given to Func to create IWebHost/IHost should be protocol://+:port. 28 | /// b. url returned from OpenAsync should be protocol://IPAddressOrFQDN:port/PartitionId/ReplicaId. 29 | /// 30 | /// 31 | /// The type of host used to create the listener. 32 | [Theory] 33 | [MemberData(nameof(HostTypes))] 34 | public void VerifyWithUseUniqueServiceUrlOption(string hostType) 35 | { 36 | var context = TestMocksRepository.GetMockStatelessServiceContext(); 37 | context.CodePackageActivationContext.GetEndpoints().Add(this.GetTestEndpoint()); 38 | this.Listener = this.CreateListener(context, EndpointName, hostType); 39 | this.UseUniqueServiceUrlOptionVerifier(); 40 | } 41 | 42 | /// 43 | /// Tests Url for ServiceFabricIntegrationOptions.None 44 | /// 1. When endpoint name is provided (protocol and port comes from endpoint.) : 45 | /// a. url given to Func to create IWebHost/IHost should be protocol://+:port. 46 | /// b. url returned from OpenAsync should be protocol://IPAddressOrFQDN:port. 47 | /// 48 | /// 49 | /// The type of host used to create the listener. 50 | [Theory] 51 | [MemberData(nameof(HostTypes))] 52 | public void VerifyWithoutUseUniqueServiceUrlOption(string hostType) 53 | { 54 | var context = TestMocksRepository.GetMockStatelessServiceContext(); 55 | context.CodePackageActivationContext.GetEndpoints().Add(this.GetTestEndpoint()); 56 | this.Listener = this.CreateListener(context, EndpointName, hostType); 57 | this.WithoutUseUniqueServiceUrlOptionVerifier(); 58 | } 59 | 60 | /// 61 | /// Verify Listener Open and Close. 62 | /// 63 | /// The type of host used to create the listener. 64 | [Theory] 65 | [MemberData(nameof(HostTypes))] 66 | public void VerifyListenerOpenClose(string hostType) 67 | { 68 | var context = TestMocksRepository.GetMockStatelessServiceContext(); 69 | context.CodePackageActivationContext.GetEndpoints().Add(this.GetTestEndpoint()); 70 | this.Listener = this.CreateListener(context, EndpointName, hostType); 71 | this.ListenerOpenCloseVerifier(); 72 | } 73 | 74 | /// 75 | /// InvalidOperationException is thrown when Endpoint is not found in service manifest. 76 | /// 77 | /// The type of host used to create the listener. 78 | [Theory] 79 | [MemberData(nameof(HostTypes))] 80 | public void ExceptionForEndpointNotFound(string hostType) 81 | { 82 | this.Listener = this.CreateListener(TestMocksRepository.GetMockStatelessServiceContext(), "NoEndPoint", hostType); 83 | this.ExceptionForEndpointNotFoundVerifier(); 84 | } 85 | 86 | /// 87 | /// ArgumentException is thrown when endpointName is null or empty string. 88 | /// 89 | /// The type of host used to create the listener. 90 | [Theory] 91 | [MemberData(nameof(HostTypes))] 92 | public void VerifyExceptionForNullOrEmptyEndpointName(string hostType) 93 | { 94 | Action action = 95 | () => 96 | this.CreateListener( 97 | TestMocksRepository.GetMockStatelessServiceContext(), 98 | null, 99 | hostType); 100 | action.Should().Throw(); 101 | 102 | action = 103 | () => 104 | this.CreateListener( 105 | TestMocksRepository.GetMockStatelessServiceContext(), 106 | string.Empty, 107 | hostType); 108 | action.Should().Throw(); 109 | } 110 | 111 | private HttpSysCommunicationListener CreateListener(StatelessServiceContext context, string endpointName, string hostType) 112 | { 113 | if (hostType == "WebHost") 114 | { 115 | return new HttpSysCommunicationListener(context, endpointName, (uri, listen) => this.IWebHostBuildFunc(uri, listen)); 116 | } 117 | else 118 | { 119 | return new HttpSysCommunicationListener(context, endpointName, (uri, listen) => this.IHostBuildFunc(uri, listen)); 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/KestrelCommunicationListenerTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Fabric; 10 | using FluentAssertions; 11 | using Microsoft.ServiceFabric.Services.Communication.AspNetCore; 12 | using Xunit; 13 | 14 | /// 15 | /// Test class for KestrelCommunicationListener. 16 | /// 17 | public class KestrelCommunicationListenerTests : AspNetCoreCommunicationListenerTests 18 | { 19 | // 1. When no endpointRef is provided: 20 | // a. url given to Func to create IWebHost/IHost should be http://+:0 21 | // b. url returned from OpenAsync should be http://IPAddressOrFQDN:0/PartitionId/ReplicaId 22 | // 23 | // 24 | 25 | /// 26 | /// Tests Url for ServiceFabricIntegrationOptions.UseUniqueServiceUrl 27 | /// 1. When endpoint name is provided (protocol and port comes from endpoint.) : 28 | /// a. url given to Func to create IWebHost/IHost should be protocol://+:port. 29 | /// b. url returned from OpenAsync should be protocol://IPAddressOrFQDN:port/PartitionId/ReplicaId. 30 | /// 31 | /// 32 | /// The type of host used to create the listener. 33 | [Theory] 34 | [MemberData(nameof(HostTypes))] 35 | public void VerifyWithUseUniqueServiceUrlOption(string hostType) 36 | { 37 | var context = TestMocksRepository.GetMockStatelessServiceContext(); 38 | context.CodePackageActivationContext.GetEndpoints().Add(this.GetTestEndpoint()); 39 | this.Listener = this.CreateListener(context, EndpointName, hostType); 40 | this.UseUniqueServiceUrlOptionVerifier(); 41 | } 42 | 43 | /// 44 | /// Tests Url for ServiceFabricIntegrationOptions.None 45 | /// 1. When endpoint name is provided (protocol and port comes from endpoint.) : 46 | /// a. url given to Func to create IWebHost/IHost should be protocol://+:port. 47 | /// b. url returned from OpenAsync should be protocol://IPAddressOrFQDN:port. 48 | /// 49 | /// 50 | /// The type of host used to create the listener. 51 | [Theory] 52 | [MemberData(nameof(HostTypes))] 53 | public void VerifyWithoutUseUniqueServiceUrlOption(string hostType) 54 | { 55 | var context = TestMocksRepository.GetMockStatelessServiceContext(); 56 | context.CodePackageActivationContext.GetEndpoints().Add(this.GetTestEndpoint()); 57 | this.Listener = this.CreateListener(context, EndpointName, hostType); 58 | this.WithoutUseUniqueServiceUrlOptionVerifier(); 59 | } 60 | 61 | /// 62 | /// Verify Listener Open and Close. 63 | /// 64 | /// The type of host used to create the listener. 65 | [Theory] 66 | [MemberData(nameof(HostTypes))] 67 | public void VerifyListenerOpenClose(string hostType) 68 | { 69 | var context = TestMocksRepository.GetMockStatelessServiceContext(); 70 | context.CodePackageActivationContext.GetEndpoints().Add(this.GetTestEndpoint()); 71 | this.Listener = this.CreateListener(context, EndpointName, hostType); 72 | this.ListenerOpenCloseVerifier(); 73 | } 74 | 75 | /// 76 | /// InvalidOperationEXception is thrown when Endpoint is not found in service manifest. 77 | /// 78 | /// The type of host used to create the listener. 79 | [Theory] 80 | [MemberData(nameof(HostTypes))] 81 | public void ExceptionForEndpointNotFound(string hostType) 82 | { 83 | this.Listener = this.CreateListener(TestMocksRepository.GetMockStatelessServiceContext(), "NoEndPoint", hostType); 84 | this.ExceptionForEndpointNotFoundVerifier(); 85 | } 86 | 87 | /// 88 | /// ArgumentException is thrown when endpointName is empty string. 89 | /// 90 | /// The type of host used to create the listener. 91 | [Theory] 92 | [MemberData(nameof(HostTypes))] 93 | public void VerifyExceptionForEmptyEndpointName(string hostType) 94 | { 95 | Action action = 96 | () => 97 | this.CreateListener( 98 | TestMocksRepository.GetMockStatelessServiceContext(), 99 | string.Empty, 100 | hostType); 101 | action.Should().Throw(); 102 | } 103 | 104 | private KestrelCommunicationListener CreateListener(StatelessServiceContext context, string endpointName, string hostType) 105 | { 106 | if (hostType == "WebHost") 107 | { 108 | return new KestrelCommunicationListener(context, endpointName, (uri, listen) => this.IWebHostBuildFunc(uri, listen)); 109 | } 110 | else 111 | { 112 | return new KestrelCommunicationListener(context, endpointName, (uri, listen) => this.IHostBuildFunc(uri, listen)); 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/KeyedCollectionImpl.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Collections.ObjectModel; 10 | 11 | /// 12 | /// Implementation for KeyedCollection to sue with AspNetCoreCommunicationListener tests. 13 | /// 14 | /// The type of keys in the collection. 15 | /// The type of items in the collection. 16 | public class KeyedCollectionImpl : KeyedCollection 17 | { 18 | private readonly Func getKey; 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// Callback method to get key. 24 | protected internal KeyedCollectionImpl(Func getKeyCallback) 25 | : base() 26 | { 27 | this.getKey = getKeyCallback; 28 | } 29 | 30 | /// 31 | /// Extracts the key from the specified element. 32 | /// 33 | /// The element from which to extract the key. 34 | /// The key for the specified element. 35 | protected override TKey GetKeyForItem(TItem item) 36 | { 37 | return this.getKey(item); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/Microsoft.ServiceFabric.AspNetCore.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Microsoft.ServiceFabric.AspNetCore.Tests 7 | Microsoft.ServiceFabric.AspNetCore.Tests 8 | net9.0 9 | $(OutputPath)\$(AssemblyName).xml 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/Mocks/MockConfigurationPackage.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Fabric; 10 | using System.Fabric.Description; 11 | using Microsoft.Extensions.Configuration; 12 | 13 | /// 14 | /// Mock implementation of the package. 15 | /// 16 | public static class MockConfigurationPackage 17 | { 18 | internal static ConfigurationPackage CreateDefaultPackage(IConfiguration config, string packageName) 19 | { 20 | var basePath = Environment.CurrentDirectory; 21 | 22 | var settings = TestHelper.CreateInstanced(); 23 | var section = TestHelper.CreateInstanced(); 24 | settings.Set(nameof(ConfigurationSettings.Sections), MockConfigurationSections.CreateDefault(config)); 25 | 26 | var desc = TestHelper.CreateInstanced(); 27 | desc.Set("Name", packageName); 28 | desc.Set("Version", "1.0"); 29 | desc.Set("Path", $"{basePath}\\{packageName}\\PackageRoot\\Config\\"); 30 | desc.Set("Settings", settings); 31 | 32 | var package = TestHelper.CreateInstanced(); 33 | package.Set("Description", desc); 34 | 35 | return package; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/Mocks/MockConfigurationProperties.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Collections.ObjectModel; 11 | using System.Fabric.Description; 12 | using System.Linq; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | using Microsoft.Extensions.Configuration; 16 | 17 | /// 18 | /// Mock implementation of ConfigurationProperties. 19 | /// 20 | public class MockConfigurationProperties : KeyedCollection 21 | { 22 | /// 23 | /// Creates the default. 24 | /// 25 | /// the mock configuration properties. 26 | internal static MockConfigurationProperties CreateDefault(IConfigurationSection section) 27 | { 28 | var parameters = new MockConfigurationProperties(); 29 | 30 | foreach (var item in section.GetChildren()) 31 | { 32 | var parameter = TestHelper.CreateInstanced(); 33 | parameter.Set("Name", item.Key); 34 | parameter.Set("Value", item.Value); 35 | parameter.Set(nameof(ConfigurationProperty.IsEncrypted), item.Key.Contains("Security") || item.Value.Contains("Security")); 36 | parameters.Add(parameter); 37 | } 38 | 39 | return parameters; 40 | } 41 | 42 | /// 43 | protected override string GetKeyForItem(ConfigurationProperty item) 44 | { 45 | return item.Name; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/Mocks/MockConfigurationSections.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Collections.ObjectModel; 10 | using System.Fabric.Description; 11 | using Microsoft.Extensions.Configuration; 12 | using ConfigurationSection = System.Fabric.Description.ConfigurationSection; 13 | 14 | /// 15 | /// Mock implementation of the sections. 16 | /// 17 | public class MockConfigurationSections : KeyedCollection 18 | { 19 | internal static MockConfigurationSections CreateDefault(IConfiguration config) 20 | { 21 | var sections = new MockConfigurationSections(); 22 | 23 | foreach (var item in config.GetChildren()) 24 | { 25 | var section = TestHelper.CreateInstanced(); 26 | section.Set("Name", item.Key); 27 | section.Set(nameof(ConfigurationSection.Parameters), MockConfigurationProperties.CreateDefault(item)); 28 | sections.Add(section); 29 | } 30 | 31 | return sections; 32 | } 33 | 34 | /// 35 | protected override string GetKeyForItem(ConfigurationSection item) 36 | { 37 | return item.Name; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/Mocks/TestHelper.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Reflection; 12 | using System.Runtime.Serialization; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | 16 | /// 17 | /// TestHelper. 18 | /// 19 | internal static class TestHelper 20 | { 21 | public static T CreateInstanced() 22 | where T : class 23 | { 24 | #pragma warning disable SYSLIB0050 // FormatterServices is obsolete 25 | return FormatterServices.GetSafeUninitializedObject(typeof(T)) as T; 26 | #pragma warning restore SYSLIB0050 27 | } 28 | 29 | public static T Set(this T instance, string property, object value) 30 | where T : class 31 | { 32 | typeof(T).GetProperty(property).SetValue(instance, value); 33 | return instance; 34 | } 35 | 36 | internal static T InvokeMember(object instance, string memberName, params object[] args) 37 | { 38 | var type = instance.GetType(); 39 | var result = type.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, instance, args); 40 | return (T)result; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/ServiceFabricConfigurationProviderTest.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using FluentAssertions; 11 | using Microsoft.Extensions.Configuration; 12 | using Microsoft.Extensions.Logging; 13 | using Microsoft.ServiceFabric.AspNetCore.Configuration; 14 | using Xunit; 15 | 16 | /// 17 | /// Test for ServiceFabricConfigurationProvider. 18 | /// 19 | public class ServiceFabricConfigurationProviderTest 20 | { 21 | private int valueCount = 0; 22 | private int sectionCount = 0; 23 | 24 | /// 25 | /// Verify that the basic types could be loaded. 26 | /// 27 | [Fact] 28 | public void TestHappyCase() 29 | { 30 | var contextConfig = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 31 | { 32 | { "Section1:Name", "Xiaoxiao" }, 33 | { "Section1:Age", "6" }, 34 | { "Section1:Gender", "M" }, 35 | { "Section2:Gender", "F" }, 36 | }).Build(); 37 | 38 | var context = new TestCodePackageActivationContext(contextConfig); 39 | var names = context.GetCodePackageNames(); 40 | names.Count.Should().Be(1, "Only 1 config package"); 41 | 42 | var builder = new ConfigurationBuilder(); 43 | builder.AddServiceFabricConfiguration(context); 44 | var config = builder.Build(); 45 | 46 | config["Config:Section1:Name"].Should().Be("Xiaoxiao"); 47 | config["Section1:Name"].Should().BeNull("Default behavior shall include the package name in key."); 48 | config["Config:Section1:Age"].Should().Be("6"); 49 | config["Config:Gender"].Should().Be(null); 50 | config["Config:Section1:Gender"].Should().Be("M"); 51 | config["Config:Section2:Gender"].Should().Be("F"); 52 | 53 | // basic validate to bind to a class directly 54 | // Note, in asp.net core 2.1 you could use the more simple ConfigurationBinder.Get binds and returns the specified type instance directly. 55 | // Get is more convenient than using Bind but will require .net core version higher than 1.0 56 | var person = new Person(); 57 | config.GetSection("Config:Section1").Bind(person); 58 | 59 | person.Name.Should().Be("Xiaoxiao"); 60 | person.Age.Should().Be(6); 61 | person.Gender.Should().Be("M"); 62 | } 63 | 64 | /// 65 | /// Verify the configuration updates. 66 | /// 67 | [Fact] 68 | public void TestConfigUpdate() 69 | { 70 | var contextConfig = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 71 | { 72 | { "Section1:Name", "Xiaoxiao" }, 73 | { "Section1:Age", "6" }, 74 | { "Section1:Gender", "M" }, 75 | }).Build(); 76 | 77 | var context = new TestCodePackageActivationContext(contextConfig); 78 | 79 | var builder = new ConfigurationBuilder(); 80 | builder.AddServiceFabricConfiguration(context); 81 | var config = builder.Build(); 82 | 83 | config["Config:Section1:Name"].Should().Be("Xiaoxiao"); 84 | config["Config:Section1:Age"].Should().Be("6"); 85 | config["Config:Section1:Gender"].Should().Be("M"); 86 | 87 | // trigger config update 88 | context.TriggerConfigurationPackageModifiedEvent( 89 | new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 90 | { 91 | { "Section1:Name", "Lele" }, 92 | { "Section1:Age", "3" }, 93 | { "Section1:Gender", "M" }, 94 | }).Build(), 95 | "Config"); 96 | 97 | config["Config:Section1:Name"].Should().Be("Lele"); 98 | config["Config:Section1:Age"].Should().Be("3"); 99 | config["Config:Section1:Gender"].Should().Be("M"); 100 | } 101 | 102 | /// 103 | /// Tests the empty configuration. 104 | /// 105 | [Fact] 106 | public void TestEmptyConfig() 107 | { 108 | var contextConfig = new ConfigurationBuilder().Build(); 109 | var context = new TestCodePackageActivationContext(contextConfig); 110 | 111 | var builder = new ConfigurationBuilder(); 112 | builder.AddServiceFabricConfiguration(context); 113 | var config = builder.Build(); 114 | 115 | config.GetChildren().Should().BeEmpty(); 116 | } 117 | 118 | /// 119 | /// Tests the multi configs. 120 | /// 121 | [Fact] 122 | public void TestMultiConfigsWithUpdate() 123 | { 124 | // Case 1: Configuration is loaded correctly from multiple providers 125 | var contextConfig1 = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 126 | { 127 | { "SameSection:Name", "Xiaoxiao" }, 128 | { "Section1:Age", "6" }, 129 | { "Section1:Gender", "M" }, 130 | }).Build(); 131 | 132 | var contextConfig2 = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 133 | { 134 | { "SameSection:Name", "Lele" }, 135 | { "Section2:Age", "3" }, 136 | { "Section2:Gender", "M" }, 137 | }).Build(); 138 | 139 | var context = new TestCodePackageActivationContext(new Dictionary() { { "Config1", contextConfig1 }, { "Config2", contextConfig2 } }); 140 | 141 | var builder = new ConfigurationBuilder(); 142 | builder.AddServiceFabricConfiguration(context); 143 | var config = builder.Build() as ConfigurationRoot; 144 | 145 | config["Config1:SameSection:Name"].Should().Be("Xiaoxiao"); 146 | config["Config1:Section1:Age"].Should().Be("6"); 147 | config["Config1:Section1:Gender"].Should().Be("M"); 148 | 149 | config["Config2:SameSection:Name"].Should().Be("Lele"); 150 | config["Config2:Section2:Age"].Should().Be("3"); 151 | config["Config2:Section2:Gender"].Should().Be("M"); 152 | 153 | // Case 2: ServiceFabricConfigurationProvider only loads configuration from the ConfigPackage it is mapped to 154 | // (and does not load from other ConfigPackages) when a config update event is triggered 155 | context.TriggerConfigurationPackageModifiedEvent( 156 | new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 157 | { 158 | { "SameSection:Name", "Jill" }, 159 | { "Section1:Age", "30" }, 160 | { "Section1:Gender", "F" }, 161 | }).Build(), 162 | "Config1"); 163 | 164 | config["Config1:SameSection:Name"].Should().Be("Jill"); 165 | config["Config1:Section1:Age"].Should().Be("30"); 166 | config["Config1:Section1:Gender"].Should().Be("F"); 167 | 168 | config["Config2:SameSection:Name"].Should().Be("Lele"); 169 | config["Config2:Section2:Age"].Should().Be("3"); 170 | config["Config2:Section2:Gender"].Should().Be("M"); 171 | } 172 | 173 | /// 174 | /// Tests the security configuration. 175 | /// 176 | [Fact] 177 | public void TestEncryptedConfig() 178 | { 179 | var contextConfig = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 180 | { 181 | // in the MockConfigurationProperties this section is special handled to turn IsEncrypted to true as follow 182 | // parameter.Set(nameof(ConfigurationProperty.IsEncrypted), item.Key.Contains("Security") || item.Value.Contains("Security")); 183 | { "SecuritySection:SecuritySSN", "EncryptedValue" }, 184 | }).Build(); 185 | 186 | var context = new TestCodePackageActivationContext(contextConfig); 187 | 188 | var builder = new ConfigurationBuilder(); 189 | builder.AddServiceFabricConfiguration(context); 190 | var config = builder.Build(); 191 | 192 | config["Config:SecuritySection:SecuritySSN"].Should().Be("EncryptedValue"); 193 | 194 | var builder2 = new ConfigurationBuilder(); 195 | 196 | // set flag to decrypt the value 197 | builder2.AddServiceFabricConfiguration(context, (options) => options.DecryptValue = true); 198 | 199 | Action config2 = () => builder2.Build(); 200 | config2.Should().Throw("Exception expected here because DecryptValue will fail here with invalid values."); 201 | } 202 | 203 | /// 204 | /// Tests the configuration action. 205 | /// 206 | [Fact] 207 | public void TestConfigAction() 208 | { 209 | var contextConfig = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 210 | { 211 | { "Section1:Name", "Xiaoxiao" }, 212 | { "Section1:Age", "6" }, 213 | }).Build(); 214 | 215 | // initial load 216 | var context = new TestCodePackageActivationContext(contextConfig); 217 | this.valueCount = 0; 218 | this.sectionCount = 0; 219 | var builder = new ConfigurationBuilder(); 220 | builder.AddServiceFabricConfiguration(context, (options) => 221 | { 222 | options.ConfigAction = (package, configData) => 223 | { 224 | using ILoggerFactory loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); 225 | ILogger logger = loggerFactory.CreateLogger("test"); 226 | logger.LogInformation($"Config Update for package {package.Path} started"); 227 | 228 | foreach (var section in package.Settings.Sections) 229 | { 230 | this.sectionCount++; 231 | 232 | foreach (var param in section.Parameters) 233 | { 234 | configData[options.ExtractKeyFunc(section, param)] = options.ExtractValueFunc(section, param); 235 | this.valueCount++; 236 | } 237 | } 238 | 239 | logger.LogInformation($"Config Update for package {package.Path} finished"); 240 | }; 241 | 242 | options.IncludePackageName = false; 243 | }); 244 | 245 | var config = builder.Build(); 246 | config["Section1:Name"].Should().Be("Xiaoxiao"); 247 | config["Section1:Age"].Should().Be("6"); 248 | this.sectionCount.Should().Be(1); 249 | this.valueCount.Should().Be(2); 250 | 251 | this.valueCount = 0; 252 | this.sectionCount = 0; 253 | 254 | // trigger config update 255 | context.TriggerConfigurationPackageModifiedEvent( 256 | new ConfigurationBuilder().AddInMemoryCollection(new Dictionary 257 | { 258 | { "Section1:Name", "Lele" }, 259 | }).Build(), "Config"); 260 | 261 | config["Section1:Name"].Should().Be("Lele"); 262 | this.sectionCount.Should().Be(1); 263 | this.valueCount.Should().Be(1); 264 | } 265 | 266 | internal class Person 267 | { 268 | public string Name { get; set; } 269 | 270 | public string Gender { get; set; } 271 | 272 | public int Age { get; set; } 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/TestMocksRepository.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Fabric; 10 | using System.Fabric.Description; 11 | using System.Numerics; 12 | using Moq; 13 | 14 | /// 15 | /// Contains mocks needed by Aspnet core listener unit tests. 16 | /// 17 | internal static class TestMocksRepository 18 | { 19 | private const long MockReplicaOrInstanceID = 99999999999; 20 | private const string MockFQDN = "MockFQDN"; 21 | private const string MockServiceTypeName = "MockServiceTypeName"; 22 | private const string MockServiceUri = "fabric:/MockServiceName"; 23 | private static Guid mockPartitionID = Guid.NewGuid(); 24 | 25 | internal static StatefulServiceContext GetMockStatefulServiceContext() 26 | { 27 | return new StatefulServiceContext( 28 | GetNodeContext(), 29 | GetCodePackageActivationContext(), 30 | MockServiceTypeName, 31 | new Uri(MockServiceUri), 32 | null, 33 | mockPartitionID, 34 | MockReplicaOrInstanceID); 35 | } 36 | 37 | internal static StatelessServiceContext GetMockStatelessServiceContext() 38 | { 39 | return new StatelessServiceContext( 40 | GetNodeContext(), 41 | GetCodePackageActivationContext(), 42 | MockServiceTypeName, 43 | new Uri(MockServiceUri), 44 | null, 45 | mockPartitionID, 46 | MockReplicaOrInstanceID); 47 | } 48 | 49 | private static NodeContext GetNodeContext() 50 | { 51 | return new NodeContext( 52 | "MockNode", 53 | new NodeId(BigInteger.Zero, BigInteger.Zero), 54 | BigInteger.Zero, 55 | "MockNodeType", 56 | MockFQDN); 57 | } 58 | 59 | private static ICodePackageActivationContext GetCodePackageActivationContext() 60 | { 61 | var endpointCollection = new KeyedCollectionImpl(x => x.Name); 62 | 63 | // Create mock Context and setup required things needed by tests. 64 | var mockContext = new Mock(); 65 | mockContext.Setup(x => x.GetEndpoints()).Returns(endpointCollection); 66 | mockContext.Setup(y => y.GetEndpoint(It.IsAny())).Returns(name => 67 | { 68 | return endpointCollection[name]; 69 | }); 70 | 71 | return mockContext.Object; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/WebHostBuilderServiceFabricExtensionTests.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------ 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT License (MIT). See License.txt in the repo root for license information. 4 | // ------------------------------------------------------------ 5 | 6 | namespace Microsoft.ServiceFabric.AspNetCore.Tests 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | using FluentAssertions; 14 | using Microsoft.AspNetCore.Hosting; 15 | using Microsoft.AspNetCore.Hosting.Server.Features; 16 | using Microsoft.AspNetCore.Http.Features; 17 | using Microsoft.Extensions.DependencyInjection; 18 | using Microsoft.ServiceFabric.Services.Communication.AspNetCore; 19 | using Moq; 20 | using Xunit; 21 | 22 | /// 23 | /// Test class for WebHostBuilderServiceFabricExtension. 24 | /// 25 | public class WebHostBuilderServiceFabricExtensionTests 26 | { 27 | private readonly Dictionary settings; 28 | private readonly AspNetCoreCommunicationListener listener; 29 | private readonly IWebHostBuilder builder; 30 | 31 | /// 32 | /// Used by test to check if services were configured by WebHostBuilderServiceFabricExtension.UseServiceFabricIntegration. 33 | /// 34 | private bool servicesConfigured; 35 | 36 | /// 37 | /// Initializes a new instance of the class. 38 | /// 39 | public WebHostBuilderServiceFabricExtensionTests() 40 | { 41 | this.settings = new Dictionary(); 42 | 43 | // create mock IWebHostBuilder to test functionality of Service Fabric WebHostBuilder extension 44 | var mockBuilder = new Mock(); 45 | 46 | // setup call backs for Getting and setting settings. 47 | mockBuilder.Setup(y => y.GetSetting(It.IsAny())).Returns(name => 48 | { 49 | this.settings.TryGetValue(name, out var value); 50 | return value; 51 | }); 52 | 53 | mockBuilder.Setup(y => y.UseSetting(It.IsAny(), It.IsAny())).Callback((name, value) => 54 | { 55 | this.settings.Add(name, value); 56 | }); 57 | 58 | mockBuilder.Setup(y => y.ConfigureServices(It.IsAny>())).Callback(() => this.servicesConfigured = true); 59 | 60 | this.builder = mockBuilder.Object; 61 | this.servicesConfigured = false; 62 | 63 | var context = TestMocksRepository.GetMockStatelessServiceContext(); 64 | this.listener = new KestrelCommunicationListener(context, (uri, listen) => this.BuildFunc(uri, listen)); 65 | } 66 | 67 | /// 68 | /// Verify WebHostBuilderExtension for ServiceFabricIntegrationOptions.None. 69 | /// 70 | [Fact] 71 | public void VerifyWithServiceFabricIntegrationOptions_None() 72 | { 73 | this.builder.UseServiceFabricIntegration(this.listener, ServiceFabricIntegrationOptions.None); 74 | this.servicesConfigured.Should().BeTrue("services are configured."); 75 | this.listener.UrlSuffix.Should().BeEmpty("listener is not Configured to use UniqueServiceUrl."); 76 | 77 | // Call the UseServiceFabricIntegration() again and verify that its dual invocation, doesn't have adverse affect. 78 | this.builder.UseServiceFabricIntegration(this.listener, ServiceFabricIntegrationOptions.None); 79 | this.servicesConfigured.Should().BeTrue("services are configured."); 80 | this.listener.UrlSuffix.Should().BeEmpty("listener is not Configured to use UniqueServiceUrl."); 81 | } 82 | 83 | /// 84 | /// Verify WebHostBuilderExtension for ServiceFabricIntegrationOptions.UseUniqueServiceUrl. 85 | /// 86 | [Fact] 87 | public void VerifyWithServiceFabricIntegrationOptions_UseUniqueServiceUrl() 88 | { 89 | // ServiceFabricIntegrationOptions.None doesn't adds middleware and doesn't configures listener to use UrlSuffix. 90 | this.builder.UseServiceFabricIntegration(this.listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl); 91 | this.servicesConfigured.Should().BeTrue("services are configured."); 92 | this.listener.UrlSuffix.Should().NotBeEmpty("listener is Configured to use UniqueServiceUrl."); 93 | 94 | // Call the UseServiceFabricIntegration() again and verify that its dual invocation, doesn't have adverse affect. 95 | this.builder.UseServiceFabricIntegration(this.listener, ServiceFabricIntegrationOptions.UseUniqueServiceUrl); 96 | this.servicesConfigured.Should().BeTrue("services are configured."); 97 | this.listener.UrlSuffix.Should().NotBeEmpty("listener is Configured to use UniqueServiceUrl."); 98 | } 99 | 100 | private IWebHost BuildFunc(string url, AspNetCoreCommunicationListener listener) 101 | { 102 | var mockServerAddressFeature = new Mock(); 103 | mockServerAddressFeature.Setup(y => y.Addresses).Returns(new string[] { url }); 104 | var featureCollection = new FeatureCollection(); 105 | featureCollection.Set(mockServerAddressFeature.Object); 106 | 107 | // Create mock IWebHost and set required things used by this test. 108 | var mockWebHost = new Mock(); 109 | return mockWebHost.Object; 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /test/unittests/Microsoft.ServiceFabric.AspNetCore.Tests/stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | // ACTION REQUIRED: This file was automatically added to your project, but it 3 | // will not take effect until additional steps are taken to enable it. See the 4 | // following page for additional information: 5 | // 6 | // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md 7 | 8 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 9 | "settings": { 10 | "documentationRules": { 11 | "companyName": "PlaceholderCompany" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/unittests/default.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | x64 5 | 6 | --------------------------------------------------------------------------------