Repository: autofac/Autofac.Extensions.DependencyInjection Branch: develop Commit: 303d9a8194cf Files: 115 Total size: 249.0 KB Directory structure: gitextract_omufirln/ ├── .editorconfig ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── build.yml │ ├── ci.yml │ ├── dotnet-format.yml │ ├── pre-commit.yml │ └── publish.yml ├── .gitignore ├── .markdownlint.json ├── .pre-commit-config.yaml ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── Autofac.Extensions.DependencyInjection.sln ├── Autofac.Extensions.DependencyInjection.sln.DotSettings ├── Autofac.snk ├── Directory.Build.props ├── LICENSE ├── README.md ├── bench/ │ └── Autofac.Extensions.DependencyInjection.Bench/ │ ├── Autofac.Extensions.DependencyInjection.Bench.csproj │ ├── AutofacWebApplicationFactory.cs │ ├── BenchWebApplicationFactory.cs │ ├── BenchmarkConfig.cs │ ├── Benchmarks.cs │ ├── DefaultWebApplicationFactory.cs │ ├── Harness.cs │ ├── KeyedResolutionBenchmark.cs │ ├── Program.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── RequestBenchmark.cs │ ├── SampleApp/ │ │ ├── Controllers/ │ │ │ └── ValuesController.cs │ │ ├── DefaultStartup.cs │ │ ├── Program.cs │ │ └── Services.cs │ └── xunit.runner.json ├── build/ │ ├── Coverage.runsettings │ ├── Source.ruleset │ ├── Test.ruleset │ └── stylecop.json ├── codecov.yml ├── default.proj ├── global.json ├── src/ │ └── Autofac.Extensions.DependencyInjection/ │ ├── Autofac.Extensions.DependencyInjection.csproj │ ├── AutofacChildLifetimeScopeConfigurationAdapter.cs │ ├── AutofacChildLifetimeScopeServiceProviderFactory.cs │ ├── AutofacRegistration.cs │ ├── AutofacServiceProvider.cs │ ├── AutofacServiceProviderFactory.cs │ ├── AutofacServiceScope.cs │ ├── AutofacServiceScopeFactory.cs │ ├── FromKeyedServicesAttributeExtensions.cs │ ├── FromKeyedServicesUsageCache.cs │ ├── KeyTypeConversionException.cs │ ├── KeyTypeConversionExceptionResources.resx │ ├── KeyTypeManipulation.cs │ ├── KeyTypeManipulationResources.resx │ ├── KeyedServiceMiddleware.cs │ ├── Polyfills/ │ │ └── NotNullWhenAttribute.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── ServiceCollectionExtensions.cs │ ├── ServiceDescriptorExtensions.cs │ ├── ServiceProviderExtensions.cs │ ├── ServiceProviderExtensionsResources.resx │ └── TypeExtensions.cs └── test/ ├── Autofac.Extensions.DependencyInjection.Integration.Test/ │ ├── Autofac.Extensions.DependencyInjection.Integration.Test.csproj │ ├── IntegrationTests.cs │ └── Properties/ │ └── AssemblyInfo.cs ├── Autofac.Extensions.DependencyInjection.Test/ │ ├── Assertions.cs │ ├── Autofac.Extensions.DependencyInjection.Test.csproj │ ├── AutofacChildLifetimeScopeConfigurationAdapterTests.cs │ ├── AutofacChildLifetimeScopeServiceProviderFactoryTests.cs │ ├── AutofacRegistrationTests.cs │ ├── AutofacServiceProviderFactoryTests.cs │ ├── AutofacServiceProviderTests.cs │ ├── FromKeyedServicesAttributeExtensionsTests.cs │ ├── FromKeyedServicesUsageCacheTests.cs │ ├── KeyTypeManipulationFixture.cs │ ├── KeyedServiceTests.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── ServiceCollectionExtensionsTests.cs │ ├── ServiceProviderExtensionsTests.cs │ ├── Specification/ │ │ ├── AssumedBehaviorTests.cs │ │ ├── BuilderAssumedBehaviorTests.cs │ │ ├── BuilderKeyedSpecificationTests.cs │ │ ├── BuilderSpecificationTests.cs │ │ ├── ChildScopeFactoryAssumedBehaviorTests.cs │ │ ├── ChildScopeFactoryKeyedSpecificationTests.cs │ │ ├── ChildScopeFactorySpecificationTests.cs │ │ ├── FactoryAssumedBehaviorTests.cs │ │ ├── FactoryKeyedSpecificationTests.cs │ │ ├── FactorySpecificationTests.cs │ │ └── MicrosoftAssumedBehaviorTests.cs │ ├── TestCulture.cs │ └── TypeExtensionsTests.cs ├── Integration.Net10/ │ ├── Controllers/ │ │ └── DateController.cs │ ├── DateProvider.cs │ ├── IDateProvider.cs │ ├── Integration.Net10.csproj │ ├── Program.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.Development.json │ └── appsettings.json └── Integration.Net8/ ├── Controllers/ │ └── DateController.cs ├── DateProvider.cs ├── IDateProvider.cs ├── Integration.Net8.csproj ├── Program.cs ├── Properties/ │ ├── AssemblyInfo.cs │ └── launchSettings.json ├── Startup.cs ├── appsettings.Development.json └── appsettings.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ ; EditorConfig to support per-solution formatting. ; Use the EditorConfig VS add-in to make this work. ; http://editorconfig.org/ ; This is the default for the codeline. root = true [*] indent_style = space trim_trailing_whitespace = true insert_final_newline = true ; .NET Code - almost, but not exactly, the same suggestions as corefx ; https://github.com/dotnet/corefx/blob/master/.editorconfig [*.cs] indent_size = 4 charset = utf-8-bom ; New line preferences csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true ; Indentation preferences csharp_indent_block_contents = true csharp_indent_braces = false csharp_indent_case_contents = true csharp_indent_case_contents_when_block = true csharp_indent_switch_labels = true csharp_indent_labels = one_less_than_current ; Modifier preferences csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:warning ; Avoid this. unless absolutely necessary dotnet_style_qualification_for_field = false:suggestion dotnet_style_qualification_for_property = false:suggestion dotnet_style_qualification_for_method = false:suggestion dotnet_style_qualification_for_event = false:suggestion ; Types: use keywords instead of BCL types, using var is fine. csharp_style_var_when_type_is_apparent = false:none dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion ; Name all constant fields using PascalCase dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = warning dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.required_modifiers = const dotnet_naming_style.pascal_case_style.capitalization = pascal_case ; Static fields should be _camelCase dotnet_naming_rule.static_fields_should_be_camel_case.severity = warning dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields dotnet_naming_rule.static_fields_should_be_camel_case.style = camel_case_underscore_style dotnet_naming_symbols.static_fields.applicable_kinds = field dotnet_naming_symbols.static_fields.required_modifiers = static dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected ; Static readonly fields should be PascalCase dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.severity = warning dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.symbols = static_readonly_fields dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.style = pascal_case_style dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field dotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly dotnet_naming_symbols.static_readonly_fields.applicable_accessibilities = private, internal, private_protected ; Internal and private fields should be _camelCase dotnet_naming_rule.camel_case_for_private_internal_fields.severity = warning dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style dotnet_naming_symbols.private_internal_fields.applicable_kinds = field dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal dotnet_naming_style.camel_case_underscore_style.required_prefix = _ dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case ; Code style defaults csharp_using_directive_placement = outside_namespace:suggestion dotnet_sort_system_directives_first = true csharp_prefer_braces = true:refactoring csharp_preserve_single_line_blocks = true:none csharp_preserve_single_line_statements = false:none csharp_prefer_static_local_function = true:suggestion csharp_prefer_simple_using_statement = false:none csharp_style_prefer_switch_expression = true:suggestion ; Code quality dotnet_style_readonly_field = true:suggestion dotnet_code_quality_unused_parameters = non_public:suggestion ; Expression-level preferences dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_auto_properties = true:suggestion dotnet_style_prefer_conditional_expression_over_assignment = true:refactoring dotnet_style_prefer_conditional_expression_over_return = true:refactoring csharp_prefer_simple_default_expression = true:suggestion # Expression-bodied members csharp_style_expression_bodied_methods = true:refactoring csharp_style_expression_bodied_constructors = true:refactoring csharp_style_expression_bodied_operators = true:refactoring csharp_style_expression_bodied_properties = true:refactoring csharp_style_expression_bodied_indexers = true:refactoring csharp_style_expression_bodied_accessors = true:refactoring csharp_style_expression_bodied_lambdas = true:refactoring csharp_style_expression_bodied_local_functions = true:refactoring # Pattern matching csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion csharp_style_pattern_matching_over_as_with_null_check = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion # Null checking preferences csharp_style_throw_expression = true:suggestion csharp_style_conditional_delegate_call = true:suggestion # Other features csharp_style_namespace_declarations = file_scoped:suggestion csharp_style_prefer_index_operator = false:none csharp_style_prefer_range_operator = false:none csharp_style_pattern_local_over_anonymous_function = false:none # Space preferences csharp_space_after_cast = false csharp_space_after_colon_in_inheritance_clause = true csharp_space_after_comma = true csharp_space_after_dot = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_after_semicolon_in_for_statement = true csharp_space_around_binary_operators = before_and_after csharp_space_around_declaration_statements = do_not_ignore csharp_space_before_colon_in_inheritance_clause = true csharp_space_before_comma = false csharp_space_before_dot = false csharp_space_before_open_square_brackets = false csharp_space_before_semicolon_in_for_statement = false csharp_space_between_empty_square_brackets = false csharp_space_between_method_call_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_declaration_name_and_open_parenthesis = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_between_square_brackets = false ; .NET project files and MSBuild - match defaults for VS [*.{csproj,nuspec,proj,projitems,props,shproj,targets,vbproj,vcxproj,vcxproj.filters,vsixmanifest,vsct}] indent_size = 2 ; .NET solution files - match defaults for VS [*.sln] end_of_line = crlf indent_style = tab ; Config - match XML and default nuget.config template [*.config] indent_size = 2 ; Resources - match defaults for VS [*.resx] indent_size = 2 ; Static analysis rulesets - match defaults for VS [*.ruleset] indent_size = 2 ; HTML, XML - match defaults for VS [*.{cshtml,html,xml}] indent_size = 4 ; JavaScript and JS mixes - match eslint settings; JSON also matches .NET Core templates [*.{js,json,ts,vue}] indent_size = 2 ; Markdown - match markdownlint settings [*.{md,markdown}] indent_size = 2 ; PowerShell - match defaults for New-ModuleManifest and PSScriptAnalyzer Invoke-Formatter [*.{ps1,psd1,psm1}] indent_size = 4 charset = utf-8-bom ; ReStructuredText - standard indentation format from examples [*.rst] indent_size = 2 # YAML - match standard YAML like Kubernetes and GitHub Actions [*.{yaml,yml}] indent_size = 2 ================================================ FILE: .gitattributes ================================================ *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain *.jpg binary *.png binary *.gif binary *.cs text=auto diff=csharp *.vb text=auto *.resx text=auto *.c text=auto *.cpp text=auto *.cxx text=auto *.h text=auto *.hxx text=auto *.py text=auto *.rb text=auto *.java text=auto *.html text=auto *.htm text=auto *.css text=auto *.scss text=auto *.sass text=auto *.less text=auto *.js text=auto *.lisp text=auto *.clj text=auto *.sql text=auto *.php text=auto *.lua text=auto *.m text=auto *.asm text=auto *.erl text=auto *.fs text=auto *.fsx text=auto *.hs text=auto *.csproj text=auto *.vbproj text=auto *.fsproj text=auto *.dbproj text=auto *.sln text=auto eol=crlf ================================================ FILE: .github/workflows/build.yml ================================================ name: Build and Test on: workflow_call: secrets: CODECOV_TOKEN: description: Token for uploading code coverage metrics to CodeCov.io. required: true jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 - name: Setup .NET uses: actions/setup-dotnet@v5 with: dotnet-version: | 8.0.x 10.0.x - name: Build and test run: dotnet msbuild ./default.proj - name: Upload coverage uses: codecov/codecov-action@v5 with: fail_ci_if_error: true files: artifacts/logs/*/coverage.cobertura.xml token: ${{ secrets.CODECOV_TOKEN }} - name: Upload package artifacts uses: actions/upload-artifact@v7 with: name: packages path: | artifacts/packages/*.nupkg artifacts/packages/*.snupkg ================================================ FILE: .github/workflows/ci.yml ================================================ name: Continuous Integration on: pull_request: branches: - develop - master push: branches: - develop - master - feature/* tags: - v[0-9]+.[0-9]+.[0-9]+ # If multiple pushes happen quickly in succession, cancel the running build and # start a new one. concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: # Linting dotnet-format: uses: ./.github/workflows/dotnet-format.yml pre-commit: uses: ./.github/workflows/pre-commit.yml # Build and test build: uses: ./.github/workflows/build.yml secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # Publish beta and release packages. publish: uses: ./.github/workflows/publish.yml needs: - build - dotnet-format - pre-commit if: ${{ github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/tags/v') }} secrets: NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} ================================================ FILE: .github/workflows/dotnet-format.yml ================================================ name: dotnet format on: workflow_call: jobs: dotnet-format: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Setup .NET 10 uses: actions/setup-dotnet@v5 with: dotnet-version: 10.0.x - name: dotnet format run: dotnet format Autofac.Extensions.DependencyInjection.sln --verify-no-changes ================================================ FILE: .github/workflows/pre-commit.yml ================================================ name: pre-commit on: workflow_call: jobs: pre-commit: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: python-version: 3.x - uses: pre-commit/action@v3.0.1 ================================================ FILE: .github/workflows/publish.yml ================================================ name: Publish on: workflow_call: secrets: NUGET_API_KEY: description: Token for publishing packages to NuGet. required: true jobs: publish: runs-on: ubuntu-latest steps: - name: Setup .NET uses: actions/setup-dotnet@v5 with: dotnet-version: 10.0.x - name: Download package artifacts uses: actions/download-artifact@v8 with: name: packages path: artifacts/packages - name: Publish to GitHub Packages run: | dotnet nuget add source --username USERNAME --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/autofac/index.json" dotnet nuget push ./artifacts/packages/*.nupkg --skip-duplicate --source github --api-key ${{ secrets.GITHUB_TOKEN }} dotnet nuget push ./artifacts/packages/*.snupkg --skip-duplicate --source github --api-key ${{ secrets.GITHUB_TOKEN }} - name: Publish to NuGet if: ${{ startsWith(github.ref, 'refs/tags/v') }} run: | dotnet nuget push ./artifacts/packages/*.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # Project specific files artifacts/ BenchmarkDotNet.Artifacts/ # User-specific files *.suo *.user *.sln.docstates *.ide Index.dat Storage.dat # Build results [Dd]ebug/ [Rr]elease/ x64/ [Bb]in/ [Oo]bj/ # Visual Studio 2015 cache/options directory .dotnet/ .vs/ .cr/ # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets !packages/*/build/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* *.TestResults.xml results/ *_i.c *_p.c *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.log *.scc # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch *.ncrunch* .*crunch*.local.xml # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.pubxml # NuGet Packages Directory packages/ # Windows Azure Build Output csx *.build.csdef # Windows Store app package directory AppPackages/ # Others sql/ *.Cache ClientBin/ [Ss]tyle[Cc]op.* !stylecop.json ~$* *~ *.dbmdl *.pfx *.publishsettings node_modules/ bower_components/ wwwroot/ project.lock.json *.Designer.cs # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file to a newer # Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files App_Data/*.mdf App_Data/*.ldf # ========================= # Windows detritus # ========================= # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Mac crap .DS_Store # JetBrains Rider .idea ================================================ FILE: .markdownlint.json ================================================ { "MD013": false } ================================================ FILE: .pre-commit-config.yaml ================================================ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: "3e8a8703264a2f4a69428a0aa4dcb512790b2c8c" # frozen: v6.0.0 hooks: - id: check-json - id: check-yaml - id: check-merge-conflict - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/igorshubovych/markdownlint-cli rev: "76b3d32d3f4b965e1d6425253c59407420ae2c43" # frozen: v0.47.0 hooks: - id: markdownlint args: - --fix - repo: https://github.com/tillig/json-sort-cli rev: "009ab2ab49e1f2fa9d6b9dfc31009ceeca055204" # frozen: v3.0.0 hooks: - id: json-sort args: - --autofix ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": [ "davidanson.vscode-markdownlint", "editorconfig.editorconfig", "ms-dotnettools.csdevkit", "travisillig.vscode-json-stable-stringify" ] } ================================================ FILE: .vscode/launch.json ================================================ { "configurations": [ { "args": [ ], "cwd": "${workspaceFolder}/test/Integration.Net8", "env": { "ASPNETCORE_ENVIRONMENT": "Development" }, "name": "Launch .NET 8 Integration Site", "preLaunchTask": "build", "program": "${workspaceFolder}/test/Integration.Net8/bin/Debug/net8.0/Integration.Net8.dll", "request": "launch", "serverReadyAction": { "action": "openExternally", "pattern": "\\bNow listening on:\\s+(https?://\\S+)", "uriFormat": "%s/date" }, "stopAtEntry": false, "type": "coreclr" }, { "args": [ ], "cwd": "${workspaceFolder}/test/Integration.Net10", "env": { "ASPNETCORE_ENVIRONMENT": "Development" }, "name": "Launch .NET 10 Integration Site", "preLaunchTask": "build", "program": "${workspaceFolder}/test/Integration.Net10/bin/Debug/net10.0/Integration.Net10.dll", "request": "launch", "serverReadyAction": { "action": "openExternally", "pattern": "\\bNow listening on:\\s+(https?://\\S+)", "uriFormat": "%s/date" }, "stopAtEntry": false, "type": "coreclr" } ], "version": "0.2.0" } ================================================ FILE: .vscode/settings.json ================================================ { "cSpell.words": [ "autofac", "cref", "diagnoser", "diagnosers", "inheritdoc", "langword", "paramref", "seealso", "typeparam", "unmanaged", "xunit" ], "coverage-gutters.coverageBaseDir": "artifacts/logs", "coverage-gutters.coverageFileNames": [ "**/coverage.cobertura.xml" ], "dotnet.defaultSolution": "Autofac.Extensions.DependencyInjection.sln", "dotnet.unitTestDebuggingOptions": { "enableStepFiltering": false, "justMyCode": false, "requireExactSource": false, "sourceLinkOptions": { "*": { "enabled": true } }, "suppressJITOptimizations": true, "symbolOptions": { "searchNuGetOrgSymbolServer": true } }, "explorer.fileNesting.enabled": true, "explorer.fileNesting.patterns": { "*.resx": "$(capture).*.resx, $(capture).designer.cs, $(capture).designer.vb" }, "files.watcherExclude": { "**/target": true } } ================================================ FILE: .vscode/tasks.json ================================================ { "linux": { "options": { "shell": { "args": [ "-NoProfile", "-Command" ], "executable": "pwsh" } } }, "osx": { "options": { "shell": { "args": [ "-NoProfile", "-Command" ], "executable": "/usr/local/bin/pwsh" } } }, "tasks": [ { "command": "If (Test-Path ${workspaceFolder}/artifacts/logs) { Remove-Item ${workspaceFolder}/artifacts/logs -Recurse -Force }; New-Item -Path ${workspaceFolder}/artifacts/logs -ItemType Directory -Force | Out-Null", "label": "create log directory", "type": "shell" }, { "args": [ "build", "${workspaceFolder}/Autofac.Extensions.DependencyInjection.sln", "--tl:off", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary" ], "command": "dotnet", "group": { "isDefault": true, "kind": "build" }, "label": "build", "problemMatcher": "$msCompile", "type": "shell" }, { "args": [ "test", "${workspaceFolder}/Autofac.Extensions.DependencyInjection.sln", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary", "--results-directory", "artifacts/logs", "--logger:trx", "--collect:XPlat Code Coverage", "--settings:build/Coverage.runsettings", "--filter", "FullyQualifiedName!~Bench" ], "command": "dotnet", "dependsOn": [ "create log directory" ], "group": { "isDefault": true, "kind": "test" }, "label": "test", "problemMatcher": "$msCompile", "type": "process" } ], "version": "2.0.0", "windows": { "options": { "shell": { "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command" ], "executable": "pwsh.exe" } } } } ================================================ FILE: Autofac.Extensions.DependencyInjection.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29201.188 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5A54DF18-E3F3-4929-876D-00650A15763E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{DEA4A8C6-DE56-4359-A87C-472FB34132E7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6B324E70-6C86-4E09-B150-CAE9DD2BADCC}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore global.json = global.json codecov.yml = codecov.yml default.proj = default.proj EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Autofac.Extensions.DependencyInjection", "src\Autofac.Extensions.DependencyInjection\Autofac.Extensions.DependencyInjection.csproj", "{513C7F7A-A758-4D48-94F4-891A00F63DA1}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Autofac.Extensions.DependencyInjection.Test", "test\Autofac.Extensions.DependencyInjection.Test\Autofac.Extensions.DependencyInjection.Test.csproj", "{911AA52A-4E68-41C5-AB24-D1618AFDF753}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bench", "bench", "{C39BE99E-D778-485B-920A-42D4EB3CBA75}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Autofac.Extensions.DependencyInjection.Bench", "bench\Autofac.Extensions.DependencyInjection.Bench\Autofac.Extensions.DependencyInjection.Bench.csproj", "{639CD744-1E61-4EF8-9E5A-9920A6BC3891}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{4072A677-5ACA-4CA4-B5EB-9B9DE7D1DD08}" ProjectSection(SolutionItems) = preProject build\Analyzers.ruleset = build\Analyzers.ruleset build\Autofac.Build.psd1 = build\Autofac.Build.psd1 build\Autofac.Build.psm1 = build\Autofac.Build.psm1 build\CodeAnalysisDictionary.xml = build\CodeAnalysisDictionary.xml EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Autofac.Extensions.DependencyInjection.Integration.Test", "test\Autofac.Extensions.DependencyInjection.Integration.Test\Autofac.Extensions.DependencyInjection.Integration.Test.csproj", "{D6217688-8E4A-4092-8D78-C4D299F27D7B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Net8", "test\Integration.Net8\Integration.Net8.csproj", "{549E4C50-7B8F-4E18-92E1-60F036B3515F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Net10", "test\Integration.Net10\Integration.Net10.csproj", "{3514BA96-C0C2-44A5-95EF-EF3F54219CDC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|ARM = Debug|ARM Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|ARM = Release|ARM Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Debug|Any CPU.Build.0 = Debug|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Debug|ARM.ActiveCfg = Debug|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Debug|ARM.Build.0 = Debug|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Debug|x64.ActiveCfg = Debug|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Debug|x64.Build.0 = Debug|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Debug|x86.ActiveCfg = Debug|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Debug|x86.Build.0 = Debug|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Release|Any CPU.ActiveCfg = Release|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Release|Any CPU.Build.0 = Release|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Release|ARM.ActiveCfg = Release|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Release|ARM.Build.0 = Release|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Release|x64.ActiveCfg = Release|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Release|x64.Build.0 = Release|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Release|x86.ActiveCfg = Release|Any CPU {513C7F7A-A758-4D48-94F4-891A00F63DA1}.Release|x86.Build.0 = Release|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Debug|Any CPU.Build.0 = Debug|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Debug|ARM.ActiveCfg = Debug|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Debug|ARM.Build.0 = Debug|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Debug|x64.ActiveCfg = Debug|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Debug|x64.Build.0 = Debug|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Debug|x86.ActiveCfg = Debug|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Debug|x86.Build.0 = Debug|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Release|Any CPU.ActiveCfg = Release|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Release|Any CPU.Build.0 = Release|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Release|ARM.ActiveCfg = Release|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Release|ARM.Build.0 = Release|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Release|x64.ActiveCfg = Release|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Release|x64.Build.0 = Release|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Release|x86.ActiveCfg = Release|Any CPU {911AA52A-4E68-41C5-AB24-D1618AFDF753}.Release|x86.Build.0 = Release|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Debug|Any CPU.Build.0 = Debug|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Debug|ARM.ActiveCfg = Debug|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Debug|ARM.Build.0 = Debug|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Debug|x64.ActiveCfg = Debug|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Debug|x64.Build.0 = Debug|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Debug|x86.ActiveCfg = Debug|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Debug|x86.Build.0 = Debug|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Release|Any CPU.ActiveCfg = Release|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Release|Any CPU.Build.0 = Release|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Release|ARM.ActiveCfg = Release|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Release|ARM.Build.0 = Release|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Release|x64.ActiveCfg = Release|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Release|x64.Build.0 = Release|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Release|x86.ActiveCfg = Release|Any CPU {639CD744-1E61-4EF8-9E5A-9920A6BC3891}.Release|x86.Build.0 = Release|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Debug|Any CPU.Build.0 = Debug|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Debug|ARM.ActiveCfg = Debug|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Debug|ARM.Build.0 = Debug|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Debug|x64.ActiveCfg = Debug|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Debug|x64.Build.0 = Debug|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Debug|x86.ActiveCfg = Debug|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Debug|x86.Build.0 = Debug|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Release|Any CPU.ActiveCfg = Release|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Release|Any CPU.Build.0 = Release|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Release|ARM.ActiveCfg = Release|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Release|ARM.Build.0 = Release|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Release|x64.ActiveCfg = Release|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Release|x64.Build.0 = Release|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Release|x86.ActiveCfg = Release|Any CPU {D6217688-8E4A-4092-8D78-C4D299F27D7B}.Release|x86.Build.0 = Release|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Debug|Any CPU.Build.0 = Debug|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Debug|ARM.ActiveCfg = Debug|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Debug|ARM.Build.0 = Debug|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Debug|x64.ActiveCfg = Debug|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Debug|x64.Build.0 = Debug|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Debug|x86.ActiveCfg = Debug|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Debug|x86.Build.0 = Debug|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Release|Any CPU.ActiveCfg = Release|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Release|Any CPU.Build.0 = Release|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Release|ARM.ActiveCfg = Release|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Release|ARM.Build.0 = Release|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Release|x64.ActiveCfg = Release|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Release|x64.Build.0 = Release|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Release|x86.ActiveCfg = Release|Any CPU {549E4C50-7B8F-4E18-92E1-60F036B3515F}.Release|x86.Build.0 = Release|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Debug|Any CPU.Build.0 = Debug|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Debug|ARM.ActiveCfg = Debug|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Debug|ARM.Build.0 = Debug|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Debug|x64.ActiveCfg = Debug|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Debug|x64.Build.0 = Debug|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Debug|x86.ActiveCfg = Debug|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Debug|x86.Build.0 = Debug|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Release|Any CPU.ActiveCfg = Release|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Release|Any CPU.Build.0 = Release|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Release|ARM.ActiveCfg = Release|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Release|ARM.Build.0 = Release|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Release|x64.ActiveCfg = Release|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Release|x64.Build.0 = Release|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Release|x86.ActiveCfg = Release|Any CPU {3514BA96-C0C2-44A5-95EF-EF3F54219CDC}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {513C7F7A-A758-4D48-94F4-891A00F63DA1} = {5A54DF18-E3F3-4929-876D-00650A15763E} {911AA52A-4E68-41C5-AB24-D1618AFDF753} = {DEA4A8C6-DE56-4359-A87C-472FB34132E7} {639CD744-1E61-4EF8-9E5A-9920A6BC3891} = {C39BE99E-D778-485B-920A-42D4EB3CBA75} {D6217688-8E4A-4092-8D78-C4D299F27D7B} = {DEA4A8C6-DE56-4359-A87C-472FB34132E7} {549E4C50-7B8F-4E18-92E1-60F036B3515F} = {DEA4A8C6-DE56-4359-A87C-472FB34132E7} {3514BA96-C0C2-44A5-95EF-EF3F54219CDC} = {DEA4A8C6-DE56-4359-A87C-472FB34132E7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {76E0A652-E5E2-4CA4-BAFD-AF6FDE0BD56A} EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35;packages\Unity.Interception.2.1.505.0\lib\NET35;packages\EnterpriseLibrary.Common.5.0.505.0\lib\NET35;packages\EnterpriseLibrary.ExceptionHandling.5.0.505.0\lib\NET35;packages\Unity.2.1.505.2\lib\NET35;packages\Unity.Interception.2.1.505.2\lib\NET35 EndGlobalSection EndGlobal ================================================ FILE: Autofac.Extensions.DependencyInjection.sln.DotSettings ================================================  True ================================================ FILE: Directory.Build.props ================================================ true ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright © 2014 Autofac Project 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: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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. ================================================ FILE: README.md ================================================ # Autofac.Extensions.DependencyInjection Autofac is an [IoC container](http://martinfowler.com/articles/injection.html) for Microsoft .NET. It manages the dependencies between classes so that **applications stay easy to change as they grow** in size and complexity. This is achieved by treating regular .NET classes as *[components](https://autofac.readthedocs.io/en/latest/glossary.html)*. [![Build status](https://ci.appveyor.com/api/projects/status/1mhkjcqr1ug80lra/branch/develop?svg=true)](https://ci.appveyor.com/project/Autofac/autofac-extensions-dependencyinjection/branch/develop) [![codecov](https://codecov.io/gh/Autofac/Autofac.Extensions.DependencyInjection/branch/develop/graph/badge.svg)](https://codecov.io/gh/Autofac/Autofac.Extensions.DependencyInjection) Please file issues and pull requests for this package in this repository rather than in the Autofac core repo. - [Documentation - .NET Core Integration](https://autofac.readthedocs.io/en/latest/integration/netcore.html) - [Documentation - ASP.NET Core Integration](https://autofac.readthedocs.io/en/latest/integration/aspnetcore.html) - [NuGet](https://www.nuget.org/packages/Autofac.Extensions.DependencyInjection) - [Contributing](https://autofac.readthedocs.io/en/latest/contributors.html) - [Open in Visual Studio Code](https://open.vscode.dev/autofac/Autofac.Extensions.DependencyInjection) ## Get Started in ASP.NET Core This quick start shows how to use the `IServiceProviderFactory{T}` integration that ASP.NET Core supports to help automatically build the root service provider for you. If you want more manual control, [check out the documentation for examples](https://autofac.readthedocs.io/en/latest/integration/aspnetcore.html). - Reference the `Autofac.Extensions.DependencyInjection` package from NuGet. - In your `Program.Main` method, where you configure the `HostBuilder`, call `UseAutofac` to hook Autofac into the startup pipeline. - In the `ConfigureServices` method of your `Startup` class register things into the `IServiceCollection` using extension methods provided by other libraries. - In the `ConfigureContainer` method of your `Startup` class register things directly into an Autofac `ContainerBuilder`. The `IServiceProvider` will automatically be created for you, so there's nothing you have to do but *register things*. ```C# public class Program { public static async Task Main(string[] args) { // The service provider factory used here allows for // ConfigureContainer to be supported in Startup with // a strongly-typed ContainerBuilder. var host = Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webHostBuilder => { webHostBuilder .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup() }) .Build(); await host.RunAsync(); } } public class Startup { public Startup(IWebHostEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); this.Configuration = builder.Build(); } public IConfiguration Configuration { get; private set; } // ConfigureServices is where you register dependencies. This gets // called by the runtime before the ConfigureContainer method, below. public void ConfigureServices(IServiceCollection services) { // Add services to the collection. Don't build or return // any IServiceProvider or the ConfigureContainer method // won't get called. services.AddOptions(); } // ConfigureContainer is where you can register things directly // with Autofac. This runs after ConfigureServices so the things // here will override registrations made in ConfigureServices. // Don't build the container; that gets done for you. If you // need a reference to the container, you need to use the // "Without ConfigureContainer" mechanism shown later. public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterModule(new AutofacModule()); } // Configure is where you add middleware. This is called after // ConfigureContainer. You can use IApplicationBuilder.ApplicationServices // here if you need to resolve things from the container. public void Configure( IApplicationBuilder app, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(this.Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseMvc(); } } ``` Our [ASP.NET Core](https://autofac.readthedocs.io/en/latest/integration/aspnetcore.html) integration documentation contains more information about using Autofac with ASP.NET Core. ## Get Help **Need help with Autofac?** We have [a documentation site](https://autofac.readthedocs.io/) as well as [API documentation](https://autofac.org/apidoc/). We're ready to answer your questions on [Stack Overflow](https://stackoverflow.com/questions/tagged/autofac) or check out the [discussion forum](https://groups.google.com/forum/#forum/autofac). ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/Autofac.Extensions.DependencyInjection.Bench.csproj ================================================  net10.0 $(NoWarn);CS1591 Exe false $([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture) latest enable true ../../build/Test.ruleset true AllEnabledByDefault enable false true true true all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/AutofacWebApplicationFactory.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.Hosting; namespace Autofac.Extensions.DependencyInjection.Bench; public sealed class AutofacWebApplicationFactory : BenchWebApplicationFactory where TStartup : class { protected override IHost CreateHost(IHostBuilder builder) { ArgumentNullException.ThrowIfNull(builder); builder.UseServiceProviderFactory(new AutofacServiceProviderFactory()); return base.CreateHost(builder); } } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/BenchWebApplicationFactory.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.IO; using System.Threading; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.Hosting; namespace Autofac.Extensions.DependencyInjection.Bench; public abstract class BenchWebApplicationFactory : WebApplicationFactory where TStartup : class { private static readonly Lazy ContentRoot = new(ResolveContentRoot, LazyThreadSafetyMode.ExecutionAndPublication); protected override void ConfigureWebHost(IWebHostBuilder builder) { ArgumentNullException.ThrowIfNull(builder); base.ConfigureWebHost(builder); builder.UseContentRoot(ContentRoot.Value); } private static string ResolveContentRoot() => Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..")); } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/BenchmarkConfig.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; namespace Autofac.Extensions.DependencyInjection.Bench; internal sealed class BenchmarkConfig : ManualConfig { private const string BenchmarkArtifactsFolder = "BenchmarkDotNet.Artifacts"; internal BenchmarkConfig() { Add(DefaultConfig.Instance); var rootFolder = AppContext.BaseDirectory.Substring(0, AppContext.BaseDirectory.LastIndexOf("bin", StringComparison.OrdinalIgnoreCase)); var runFolder = DateTime.Now.ToString("u").Replace(' ', '_').Replace(':', '-'); ArtifactsPath = Path.Combine(rootFolder, BenchmarkArtifactsFolder, runFolder); AddDiagnoser(MemoryDiagnoser.Default); } } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/Benchmarks.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Autofac.Extensions.DependencyInjection.Bench; public static class Benchmarks { public static readonly Type[] All = { typeof(RequestBenchmark), typeof(KeyedResolutionBenchmark), }; } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/DefaultWebApplicationFactory.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Autofac.Extensions.DependencyInjection.Bench; public sealed class DefaultWebApplicationFactory : BenchWebApplicationFactory where TStartup : class { } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/Harness.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using BenchmarkDotNet.Running; namespace Autofac.Extensions.DependencyInjection.Bench; public class Harness { [Fact] public void Request() => RunBenchmark(); [Fact] public void KeyedResolution() => RunBenchmark(); /// /// This method is used to enforce that benchmark types are added to /// so that they can be used directly from the command line in as well. /// private static void RunBenchmark() { var targetType = typeof(TBenchmark); var benchmarkType = Benchmarks.All.Single(type => type == targetType); BenchmarkRunner.Run(benchmarkType, new BenchmarkConfig()); } } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/KeyedResolutionBenchmark.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; using MicrosoftServiceKey = Microsoft.Extensions.DependencyInjection.ServiceKeyAttribute; namespace Autofac.Extensions.DependencyInjection.Bench; [MemoryDiagnoser] [SuppressMessage("CA1001", "CA1001", Justification = "Benchmark disposal happens in GlobalCleanup.")] public class KeyedResolutionBenchmark { private const string AlphaKey = "alpha"; private const string BetaKey = "beta"; private const string ServiceKeyAwareKey = "gamma"; private const string CombinedKey = "combined"; private AutofacServiceProvider _serviceProvider = null!; private ILifetimeScope _rootScope = null!; [GlobalSetup] public void Setup() { var services = new ServiceCollection(); services.AddTransient(); services.AddKeyedTransient(AlphaKey); services.AddKeyedTransient(BetaKey); services.AddKeyedTransient(ServiceKeyAwareKey); services.AddTransient(); services.AddKeyedTransient(CombinedKey); var builder = new ContainerBuilder(); builder.Populate(services); _rootScope = builder.Build(); _serviceProvider = new AutofacServiceProvider(_rootScope); } [GlobalCleanup] public void Cleanup() { _serviceProvider.Dispose(); } [Benchmark(Baseline = true)] public int StandardTypedResolution() { return _serviceProvider.GetRequiredService().Value; } [Benchmark] public int KeyedResolutionWithoutAttributes() { return _serviceProvider.GetRequiredKeyedService(AlphaKey).Value; } [Benchmark] public int KeyedResolutionWithServiceKeyAttribute() { return _serviceProvider.GetRequiredKeyedService(ServiceKeyAwareKey).Value; } [Benchmark] public int KeyedResolutionWithFromKeyedServicesAttribute() { return _serviceProvider.GetRequiredService().Value; } [Benchmark] public int KeyedResolutionWithBothAttributes() { return _serviceProvider.GetRequiredKeyedService(CombinedKey).Value; } [Benchmark] public int KeyedResolutionWithAnyKey() { var result = _serviceProvider.GetKeyedServices(KeyedService.AnyKey); var total = 0; foreach (var service in result) { total += service.Value; } return total; } private interface IService { int Value { get; } } private sealed class DefaultService : IService { public int Value => 1; } private sealed class AlphaService : IService { public int Value => 2; } private sealed class BetaService : IService { public int Value => 3; } private sealed class FromKeyedServicesConsumer { private readonly IService _service; public FromKeyedServicesConsumer([FromKeyedServices(BetaKey)] IService service) { _service = service; } public int Value => _service.Value; } private sealed class CombinedConsumer { private readonly IService _fromKeyedService; private readonly object? _requestedKey; public CombinedConsumer( [FromKeyedServices(BetaKey)] IService fromKeyedService, [MicrosoftServiceKey] object? requestedKey) { _fromKeyedService = fromKeyedService; _requestedKey = requestedKey; } public int Value { get { var keyValue = _requestedKey is string s ? s.Length : 0; return _fromKeyedService.Value + keyValue; } } } private sealed class ServiceKeyAwareService : IService { private readonly string _resolvedKey; public ServiceKeyAwareService([MicrosoftServiceKey] string resolvedKey) { _resolvedKey = resolvedKey; } public int Value => _resolvedKey.Length; } } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/Program.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using BenchmarkDotNet.Jobs; using BenchmarkDotNet.Running; using Microsoft.Extensions.Hosting; namespace Autofac.Extensions.DependencyInjection.Bench; public sealed class Program { private Program() { } public static void Main(string[] args) { ArgumentNullException.ThrowIfNull(args); var (filteredArgs, baselineVersion) = ExtractBaselineVersion(args); // Usage: // // Just run the benchmark with the source code version of the project: // dotnet run -c Release -p bench/Autofac.Extensions.DependencyInjection.Bench // // Run the benchmark comparing the source code version to a specific package version: // dotnet run -c Release -p bench/Autofac.Extensions.DependencyInjection.Bench -- --baseline-version 9.0.0 var config = new BenchmarkConfig(); config.AddJob( Job.InProcess .WithId("Source")); if (!string.IsNullOrWhiteSpace(baselineVersion)) { config.AddJob( Job.Default .WithId($"Package-{baselineVersion}") .AsBaseline() .WithMsBuildArguments( "/p:UseProjectReference=false", $"/p:BaselinePackageVersion={baselineVersion}")); } new BenchmarkSwitcher(Benchmarks.All).Run(filteredArgs, config); } public static IHostBuilder CreateHostBuilder(string[] args) => SampleApp.Program.CreateHostBuilder(args); private static (string[] RemainingArgs, string? BaselineVersion) ExtractBaselineVersion(string[] args) { var forwarded = new List(args.Length); string? baseline = null; for (var i = 0; i < args.Length; i++) { var arg = args[i]; if (TryMatchBaselineArg(arg, out var inlineVersion)) { if (!string.IsNullOrWhiteSpace(inlineVersion)) { baseline = inlineVersion; continue; } if (i + 1 >= args.Length) { throw new ArgumentException("Missing version value for baseline argument.", nameof(args)); } baseline = args[++i]; continue; } forwarded.Add(arg); } return (forwarded.ToArray(), baseline); } private static bool TryMatchBaselineArg(string arg, out string? valueFromAssignment) { valueFromAssignment = null; static bool Matches(string candidate) => candidate.Equals("--baseline-version", StringComparison.OrdinalIgnoreCase) || candidate.Equals("--baselineVersion", StringComparison.OrdinalIgnoreCase); var equalsIndex = arg.AsSpan().IndexOf('='); if (equalsIndex >= 0) { var prefix = arg[..equalsIndex]; if (Matches(prefix)) { valueFromAssignment = arg[(equalsIndex + 1)..]; return true; } return false; } return Matches(arg); } } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/Properties/AssemblyInfo.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. [assembly: CLSCompliant(false)] ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/RequestBenchmark.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Diagnostics.CodeAnalysis; using System.Net; using Microsoft.AspNetCore.Mvc.Testing; namespace Autofac.Extensions.DependencyInjection.Bench; [SuppressMessage("CA1001", "CA1001", Justification = "Benchmark disposal happens in a global cleanup method.")] public class RequestBenchmark { private static readonly Uri ValuesUri = new("/api/values", UriKind.Relative); private WebApplicationFactory _defaultFactory = null!; private WebApplicationFactory _autofacFactory = null!; private HttpClient _defaultClient = null!; private HttpClient _autofacClient = null!; [GlobalSetup] public void Setup() { _defaultFactory = new DefaultWebApplicationFactory(); _autofacFactory = new AutofacWebApplicationFactory(); _defaultClient = _defaultFactory.CreateClient(); _autofacClient = _autofacFactory.CreateClient(); } [GlobalCleanup] public void Cleanup() { _defaultFactory.Dispose(); _autofacFactory.Dispose(); } [Benchmark(Baseline = true)] public async Task RequestDefaultDI() { var response = await _defaultClient.GetAsync(ValuesUri).ConfigureAwait(false); if (response.StatusCode != HttpStatusCode.OK) { throw new HttpRequestException(); } } [Benchmark] public async Task RequestAutofacDI() { var response = await _autofacClient.GetAsync(ValuesUri).ConfigureAwait(false); if (response.StatusCode != HttpStatusCode.OK) { throw new HttpRequestException(); } } } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/SampleApp/Controllers/ValuesController.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.AspNetCore.Mvc; namespace Autofac.Extensions.DependencyInjection.Bench.SampleApp.Controllers; [Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private readonly A _service; public ValuesController(A service) { _service = service; } [HttpGet] public IActionResult Get() { return Ok(200); } } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/SampleApp/DefaultStartup.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace Autofac.Extensions.DependencyInjection.Bench.SampleApp; public class DefaultStartup { public DefaultStartup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/SampleApp/Program.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace Autofac.Extensions.DependencyInjection.Bench.SampleApp; public sealed class Program { private Program() { } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging(logging => { logging.SetMinimumLevel(LogLevel.Warning); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); } ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/SampleApp/Services.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. #pragma warning disable SA1402, SA1649 namespace Autofac.Extensions.DependencyInjection.Bench.SampleApp; public class A { public A(B1 b1, B2 b2) { } } public class B1 { public B1(B2 b2, C1 c1, C2 c2) { } } public class B2 { public B2(C1 c1, C2 c2) { } } public class C1 { public C1(C2 c2, D1 d1, D2 d2) { } } public class C2 { public C2(D1 d1, D2 d2) { } } public class D1 { } public class D2 { } #pragma warning restore SA1402, SA1649 ================================================ FILE: bench/Autofac.Extensions.DependencyInjection.Bench/xunit.runner.json ================================================ { "shadowCopy": false } ================================================ FILE: build/Coverage.runsettings ================================================ cobertura [System.*]* **/LoggerMessage.g.cs GeneratedCodeAttribute false true false ================================================ FILE: build/Source.ruleset ================================================  ================================================ FILE: build/Test.ruleset ================================================  ================================================ FILE: build/stylecop.json ================================================ { "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", "settings": { "documentationRules": { "companyName": "Autofac Project", "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} License. See {licenseFile} in the project root for license information.", "variables": { "licenseFile": "LICENSE", "licenseName": "MIT" }, "xmlHeader": false } } } ================================================ FILE: codecov.yml ================================================ codecov: branch: develop require_ci_to_pass: true coverage: status: project: default: threshold: 1% ================================================ FILE: default.proj ================================================ 11.0.0 Autofac.Extensions.DependencyInjection Release $([System.IO.Path]::Combine($(MSBuildProjectDirectory),"artifacts")) $([System.IO.Path]::Combine($(ArtifactDirectory),"packages")) $([System.IO.Path]::Combine($(ArtifactDirectory),"logs")) $([System.IO.Path]::Combine($(MSBuildProjectDirectory),'build/Coverage.runsettings')) $([System.DateTimeOffset]::UtcNow.ToString('yyyyMMddTHHmmssZ')) $(Version)-local $(Version) $(Version)-beta$(BuildDateTime) $(Version)-alpha$(BuildDateTime) ================================================ FILE: global.json ================================================ { "sdk": { "rollForward": "latestFeature", "version": "10.0.100" } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/Autofac.Extensions.DependencyInjection.csproj ================================================  Autofac.Extensions.DependencyInjection Autofac.Extensions.DependencyInjection Autofac implementation of the interfaces in Microsoft.Extensions.DependencyInjection.Abstractions, the .NET Framework dependency injection abstraction. Copyright © 2015 Autofac Contributors Autofac Contributors Autofac Autofac ../../Autofac.snk true en-US net10.0;net8.0;netstandard2.1;netstandard2.0 latest enable true ../../build/Source.ruleset true AllEnabledByDefault enable Autofac.Extensions.DependencyInjection autofac;di;ioc;dependencyinjection;aspnet;aspnetcore Release notes are at https://github.com/autofac/Autofac.Extensions.DependencyInjection/releases icon.png https://autofac.org MIT README.md git https://github.com/autofac/Autofac.Extensions.DependencyInjection true true true true snupkg PrepareResources;$(CompileDependsOn) $(NoWarn);8765;8600;8601;8602;8603;8604 all all MSBuild:Compile CSharp $(IntermediateOutputPath)%(Filename).Designer.cs %(Filename) Autofac.Extensions.DependencyInjection Autofac.Extensions.DependencyInjection Autofac.Extensions.DependencyInjection ================================================ FILE: src/Autofac.Extensions.DependencyInjection/AutofacChildLifetimeScopeConfigurationAdapter.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Autofac.Extensions.DependencyInjection; /// /// Configuration adapter for . /// public class AutofacChildLifetimeScopeConfigurationAdapter { private readonly List> _configurationActions = new(); /// /// Gets the list of configuration actions to be executed on the for the child . /// public IReadOnlyList> ConfigurationActions => _configurationActions; /// /// Adds a configuration action that will be executed when the child is created. /// /// Action on a that adds component registrations to the container. /// Throws when the passed configuration-action is null. public void Add(Action configurationAction) { if (configurationAction == null) { throw new ArgumentNullException(nameof(configurationAction)); } _configurationActions.Add(configurationAction); } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/AutofacChildLifetimeScopeServiceProviderFactory.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// A factory for creating a that wraps a child created from an existing parent . /// public class AutofacChildLifetimeScopeServiceProviderFactory : IServiceProviderFactory { private static readonly Action FallbackConfigurationAction = builder => { }; private readonly Action _containerConfigurationAction; private readonly ILifetimeScope _rootLifetimeScope; /// /// Initializes a new instance of the class. /// /// A function to retrieve the root instance. /// Action on a that adds component registrations to the container. public AutofacChildLifetimeScopeServiceProviderFactory(Func rootLifetimeScopeAccessor, Action? configurationAction = null) { if (rootLifetimeScopeAccessor == null) { throw new ArgumentNullException(nameof(rootLifetimeScopeAccessor)); } _rootLifetimeScope = rootLifetimeScopeAccessor(); _containerConfigurationAction = configurationAction ?? FallbackConfigurationAction; } /// /// Initializes a new instance of the class. /// /// The root instance. /// Action on a that adds component registrations to the container. public AutofacChildLifetimeScopeServiceProviderFactory(ILifetimeScope rootLifetimeScope, Action? configurationAction = null) { _rootLifetimeScope = rootLifetimeScope ?? throw new ArgumentNullException(nameof(rootLifetimeScope)); _containerConfigurationAction = configurationAction ?? FallbackConfigurationAction; } /// /// Creates a container builder from an . /// /// The collection of services. /// A container builder that can be used to create an . public AutofacChildLifetimeScopeConfigurationAdapter CreateBuilder(IServiceCollection services) { var actions = new AutofacChildLifetimeScopeConfigurationAdapter(); actions.Add(builder => builder.Populate(services)); actions.Add(builder => _containerConfigurationAction(builder)); return actions; } /// /// Creates an from the container builder. /// /// The adapter holding configuration applied to creating the . /// An . public IServiceProvider CreateServiceProvider(AutofacChildLifetimeScopeConfigurationAdapter containerBuilder) { if (containerBuilder == null) { throw new ArgumentNullException(nameof(containerBuilder)); } var scope = _rootLifetimeScope.BeginLifetimeScope(scopeBuilder => { foreach (var action in containerBuilder.ConfigurationActions) { action(scopeBuilder); } }); return new AutofacServiceProvider(scope); } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/AutofacRegistration.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Reflection; using Autofac.Builder; using Autofac.Core; using Autofac.Core.Activators; using Autofac.Core.Activators.Delegate; using Autofac.Core.Activators.Reflection; using Autofac.Core.Resolving.Pipeline; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// Extension methods for registering ASP.NET Core dependencies with Autofac. /// public static class AutofacRegistration { /// /// Populates the Autofac container builder with the set of registered service descriptors /// and makes and /// available in the container. /// /// /// The into which the registrations should be made. /// /// /// The set of service descriptors to register in the container. /// public static void Populate( this ContainerBuilder builder, IEnumerable descriptors) { Populate(builder, descriptors, null); } /// /// Populates the Autofac container builder with the set of registered service descriptors /// and makes and /// available in the container. Using this overload is incompatible with the ASP.NET Core /// support for . /// /// /// The into which the registrations should be made. /// /// /// The set of service descriptors to register in the container. /// /// /// If provided and not then all registrations with lifetime are registered /// using /// with provided /// instead of using . /// /// /// /// Specifying a addresses a specific case where you have /// an application that uses Autofac but where you need to isolate a set of services in a child scope. For example, /// if you have a large application that self-hosts ASP.NET Core items, you may want to isolate the ASP.NET /// Core registrations in a child lifetime scope so they don't show up for the rest of the application. /// This overload allows that. Note it is the developer's responsibility to execute this and create an /// using the child lifetime scope. /// /// public static void Populate( this ContainerBuilder builder, IEnumerable descriptors, object? lifetimeScopeTagForSingletons) { if (descriptors is null) { throw new ArgumentNullException(nameof(descriptors)); } if (builder is null) { throw new ArgumentNullException(nameof(builder)); } builder.RegisterType() .As() .As() .As() .As() .ExternallyOwned(); // Issue #83: IServiceScopeFactory must be a singleton and scopes must be flat, not hierarchical. builder .RegisterType() .As() .SingleInstance(); // Shims for keyed service compatibility. builder.ComponentRegistryBuilder.Registered += AddFromKeyedServiceParameterMiddleware; Register(builder, descriptors, lifetimeScopeTagForSingletons); } /// /// Inspect each component registration, and determine whether or not we can avoid adding the /// parameter to the resolve pipeline. /// private static void AddFromKeyedServiceParameterMiddleware(object? sender, ComponentRegisteredEventArgs e) { var needFromKeyedServiceParameter = false; // We can optimize quite significantly in the case where we are using // the reflection activator. In that state we can inspect the // constructors ahead of time and determine whether the parameter will // even need to be added. if (e.ComponentRegistration.Activator is ReflectionActivator reflectionActivator) { needFromKeyedServiceParameter = FromKeyedServicesUsageCache.RequiresFromKeyedServicesMiddleware(reflectionActivator); } else if (e.ComponentRegistration.Activator is DelegateActivator) { // For delegate activation there are very few paths that would let // the FromKeyedServicesAttribute actually work, and none that MEDI // supports directly. // // We're explicitly choosing here not to support [FromKeyedServices] // on the Autofac-specific generic delegate resolve methods, to // improve performance for the 99% case of other delegates that only // receive an IComponentContext or an IServiceProvider. needFromKeyedServiceParameter = false; } else if (e.ComponentRegistration.Activator is InstanceActivator) { // Instance activators don't use parameters. needFromKeyedServiceParameter = false; } else { // Unknown activator, assume we need the parameter. needFromKeyedServiceParameter = true; } e.ComponentRegistration.PipelineBuilding += (sender, pipeline) => { if (needFromKeyedServiceParameter) { pipeline.Use(KeyedServiceMiddleware.InstanceWithFromKeyedServicesParameter, MiddlewareInsertionMode.StartOfPhase); } else { pipeline.Use(KeyedServiceMiddleware.InstanceWithoutFromKeyedServicesParameter, MiddlewareInsertionMode.StartOfPhase); } }; } /// /// Configures the exposed service type on a service registration. /// /// The activator data type. /// The object registration style. /// The registration being built. /// The service descriptor with service type and key information. /// /// The , configured with the proper service type, /// and available for additional configuration. /// private static IRegistrationBuilder ConfigureServiceType( this IRegistrationBuilder registrationBuilder, ServiceDescriptor descriptor) { // If it's keyed, the service key won't be null. A null key results in it _not_ being a keyed service. if (descriptor.IsKeyedService) { var key = descriptor.ServiceKey!; if (key.Equals(Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey)) { key = Autofac.Core.KeyedService.AnyKey; } registrationBuilder.Keyed(key, descriptor.ServiceType); } else { registrationBuilder.As(descriptor.ServiceType); } return registrationBuilder; } /// /// Configures the lifecycle on a service registration. /// /// The activator data type. /// The object registration style. /// The registration being built. /// The lifecycle specified on the service registration. /// /// If not then all registrations with lifetime are registered /// using /// with provided /// instead of using . /// /// /// The , configured with the proper lifetime scope, /// and available for additional configuration. /// private static IRegistrationBuilder ConfigureLifecycle( this IRegistrationBuilder registrationBuilder, ServiceLifetime lifecycleKind, object? lifetimeScopeTagForSingleton) { switch (lifecycleKind) { case ServiceLifetime.Singleton: if (lifetimeScopeTagForSingleton == null) { registrationBuilder.SingleInstance(); } else { registrationBuilder.InstancePerMatchingLifetimeScope(lifetimeScopeTagForSingleton); } break; case ServiceLifetime.Scoped: registrationBuilder.InstancePerLifetimeScope(); break; case ServiceLifetime.Transient: registrationBuilder.InstancePerDependency(); break; } return registrationBuilder; } /// /// Populates the Autofac container builder with the set of registered service descriptors. /// /// /// The into which the registrations should be made. /// /// /// The set of service descriptors to register in the container. /// /// /// If not then all registrations with lifetime are registered /// using /// with provided /// instead of using . /// [SuppressMessage("CA2000", "CA2000", Justification = "Registrations created here are disposed when the built container is disposed.")] private static void Register( ContainerBuilder builder, IEnumerable descriptors, object? lifetimeScopeTagForSingletons) { foreach (var descriptor in descriptors) { var implementationType = descriptor.NormalizedImplementationType(); if (implementationType != null) { // Test if an open generic type is being registered var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo(); if (serviceTypeInfo.IsGenericTypeDefinition) { builder .RegisterGeneric(implementationType) .ConfigureServiceType(descriptor) .ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons); } else { builder .RegisterType(implementationType) .ConfigureServiceType(descriptor) .ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons); } continue; } if (descriptor.IsKeyedService && descriptor.KeyedImplementationFactory != null) { var registration = RegistrationBuilder.ForDelegate(descriptor.ServiceType, (context, parameters) => { // At this point the context is always a ResolveRequestContext, which will expose the actual service type. var requestContext = (ResolveRequestContext)context; var serviceProvider = context.Resolve(); var keyedService = (Autofac.Core.KeyedService)requestContext.Service; var key = requestContext.Parameters.KeyedServiceKey(); return descriptor.KeyedImplementationFactory(serviceProvider, key); }) .ConfigureServiceType(descriptor) .ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons) .CreateRegistration(); builder.RegisterComponent(registration); continue; } else if (!descriptor.IsKeyedService && descriptor.ImplementationFactory != null) { var registration = RegistrationBuilder.ForDelegate(descriptor.ServiceType, (context, parameters) => { var serviceProvider = context.Resolve(); return descriptor.ImplementationFactory(serviceProvider); }) .ConfigureServiceType(descriptor) .ConfigureLifecycle(descriptor.Lifetime, lifetimeScopeTagForSingletons) .CreateRegistration(); builder.RegisterComponent(registration); continue; } // It's not a type or factory, so it must be an instance. builder .RegisterInstance(descriptor.NormalizedImplementationInstance()!) .ConfigureServiceType(descriptor) .ConfigureLifecycle(descriptor.Lifetime, null) .ExternallyOwned(); } } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/AutofacServiceProvider.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Autofac.Core; using Microsoft.Extensions.DependencyInjection; using KeyedService = Autofac.Core.KeyedService; namespace Autofac.Extensions.DependencyInjection; /// /// Autofac implementation of the ASP.NET Core . /// /// /// public class AutofacServiceProvider : IServiceProvider, ISupportRequiredService, IKeyedServiceProvider, IServiceProviderIsService, IServiceProviderIsKeyedService, IDisposable, IAsyncDisposable { private readonly ILifetimeScope _lifetimeScope; private bool _disposed; /// /// Initializes a new instance of the class. /// /// /// The lifetime scope from which services will be resolved. /// public AutofacServiceProvider(ILifetimeScope lifetimeScope) { _lifetimeScope = lifetimeScope ?? throw new ArgumentNullException(nameof(lifetimeScope)); } /// /// Gets the underlying instance of . /// public ILifetimeScope LifetimeScope => _lifetimeScope; /// /// Gets the service object of the specified type. /// /// /// An object that specifies the type of service object to get. /// /// /// An object that specifies the key of service object to get. /// /// /// A service object of type ; or /// if there is no service object of type . /// public object? GetKeyedService(Type serviceType, object? serviceKey) { if (serviceType is null) { throw new ArgumentNullException(nameof(serviceType)); } var normalizedKey = NormalizeServiceKey(serviceType, serviceKey); if (normalizedKey is null) { // A null key equates to "not keyed." return _lifetimeScope.ResolveOptional(serviceType); } else { try { return _lifetimeScope.ResolveOptionalService(new KeyedService(normalizedKey, serviceType)); } catch (DependencyResolutionException ex) { // All exceptions resolving keyed services as of .NET 10 are // expected to be InvalidOperationException. throw new InvalidOperationException(ex.Message, ex); } } } /// /// Gets service of type from the /// and requires it be present. /// /// /// An object that specifies the type of service object to get. /// /// /// An object that specifies the key of service object to get. /// /// /// A service object of type . /// /// /// Thrown if the isn't registered with the container. /// /// /// Thrown if the object can't be resolved from the container. /// public object GetRequiredKeyedService(Type serviceType, object? serviceKey) { if (serviceType is null) { throw new ArgumentNullException(nameof(serviceType)); } var normalizedKey = NormalizeServiceKey(serviceType, serviceKey); if (normalizedKey is null) { // A null key equates to "not keyed." return _lifetimeScope.Resolve(serviceType); } else { try { return _lifetimeScope.ResolveKeyed(normalizedKey, serviceType); } catch (DependencyResolutionException ex) { // All exceptions resolving keyed services as of .NET 10 are // expected to be InvalidOperationException. throw new InvalidOperationException(ex.Message, ex); } } } /// /// Gets service of type from the /// and requires it be present. /// /// /// An object that specifies the type of service object to get. /// /// /// A service object of type . /// /// /// Thrown if the isn't registered with the container. /// /// /// Thrown if the object can't be resolved from the container. /// public object GetRequiredService(Type serviceType) { try { return _lifetimeScope.Resolve(serviceType); } catch (DependencyResolutionException ex) { throw new InvalidOperationException(ex.Message, ex); } } /// public bool IsKeyedService(Type serviceType, object? serviceKey) { // Null service key means non-keyed. if (serviceKey == null) { return IsService(serviceType); } return _lifetimeScope.ComponentRegistry.IsRegistered(new KeyedService(serviceKey, serviceType)); } /// public bool IsService(Type serviceType) => _lifetimeScope.ComponentRegistry.IsRegistered(new TypedService(serviceType)); /// /// Gets the service object of the specified type. /// /// /// An object that specifies the type of service object to get. /// /// /// A service object of type ; or /// if there is no service object of type . /// public object? GetService(Type serviceType) { try { return _lifetimeScope.ResolveOptional(serviceType); } catch (DependencyResolutionException ex) { throw new InvalidOperationException(ex.Message, ex); } } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Performs a dispose operation asynchronously. /// /// A task to await disposal. public async ValueTask DisposeAsync() { if (!_disposed) { _disposed = true; await _lifetimeScope.DisposeAsync().ConfigureAwait(false); GC.SuppressFinalize(this); } } /// /// Releases unmanaged and - optionally - managed resources. /// /// /// to release both managed and unmanaged resources; /// to release only unmanaged resources. /// protected virtual void Dispose(bool disposing) { if (!_disposed) { _disposed = true; if (disposing) { _lifetimeScope.Dispose(); } } } private static object? NormalizeServiceKey(Type serviceType, object? serviceKey) { if (serviceKey is null) { return null; } if (ReferenceEquals(serviceKey, Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey)) { if (!serviceType.IsCollection()) { throw new InvalidOperationException("KeyedService.AnyKey cannot be used to resolve a single service."); } return KeyedService.AnyKey; } return serviceKey; } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/AutofacServiceProviderFactory.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Autofac.Builder; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// A factory for creating a and an . /// public class AutofacServiceProviderFactory : IServiceProviderFactory { private static readonly Action FallbackConfigurationAction = builder => { }; private readonly Action _configurationAction; private readonly ContainerBuildOptions _containerBuildOptions = ContainerBuildOptions.None; /// /// Initializes a new instance of the class. /// /// The container options to use when building the container. /// Action on a that adds component registrations to the container. public AutofacServiceProviderFactory( ContainerBuildOptions containerBuildOptions, Action? configurationAction = null) : this(configurationAction) => _containerBuildOptions = containerBuildOptions; /// /// Initializes a new instance of the class. /// /// Action on a that adds component registrations to the container.. public AutofacServiceProviderFactory(Action? configurationAction = null) => _configurationAction = configurationAction ?? FallbackConfigurationAction; /// /// Creates a container builder from an . /// /// The collection of services. /// A container builder that can be used to create an . public ContainerBuilder CreateBuilder(IServiceCollection services) { var builder = new ContainerBuilder(); builder.Populate(services); _configurationAction(builder); return builder; } /// /// Creates an from the container builder. /// /// The container builder. /// An . public IServiceProvider CreateServiceProvider(ContainerBuilder containerBuilder) { if (containerBuilder == null) { throw new ArgumentNullException(nameof(containerBuilder)); } var container = containerBuilder.Build(_containerBuildOptions); return new AutofacServiceProvider(container); } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/AutofacServiceScope.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// Autofac implementation of the ASP.NET Core . /// Inherits from to avoid a separate /// allocation per scope — every scope is itself a service provider. /// /// internal class AutofacServiceScope : AutofacServiceProvider, IServiceScope { /// /// Initializes a new instance of the class. /// /// /// The lifetime scope from which services should be resolved for this service scope. /// public AutofacServiceScope(ILifetimeScope lifetimeScope) : base(lifetimeScope) { } /// /// Gets an corresponding to this service scope. /// /// /// An that can be used to resolve dependencies from the scope. /// public IServiceProvider ServiceProvider => this; } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/AutofacServiceScopeFactory.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// Autofac implementation of the ASP.NET Core . /// /// internal class AutofacServiceScopeFactory : IServiceScopeFactory { private readonly ILifetimeScope _lifetimeScope; /// /// Initializes a new instance of the class. /// /// The lifetime scope. public AutofacServiceScopeFactory(ILifetimeScope lifetimeScope) { _lifetimeScope = lifetimeScope; } /// /// Creates an which contains an /// used to resolve dependencies within /// the scope. /// /// /// An controlling the lifetime of the scope. Once /// this is disposed, any scoped services that have been resolved /// from the /// will also be disposed. /// public IServiceScope CreateScope() { return new AutofacServiceScope(_lifetimeScope.BeginLifetimeScope()); } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/FromKeyedServicesAttributeExtensions.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Globalization; using System.Reflection; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// Extensions for working with . /// internal static class FromKeyedServicesAttributeExtensions { /// /// Resolves a constructor parameter based on keyed service requirements. /// /// The attribute marking the keyed service dependency in a constructor. /// The specific parameter being resolved that is marked with this attribute. /// The component context under which the parameter is being resolved. /// The key used for the containing resolve request. /// /// The instance of the object that should be used for the parameter value. /// /// /// Thrown if or is . /// public static object? ResolveParameter(this FromKeyedServicesAttribute attribute, ParameterInfo parameter, IComponentContext context, object? parentServiceKey) { if (attribute is null) { throw new ArgumentNullException(nameof(attribute)); } if (parameter is null) { throw new ArgumentNullException(nameof(parameter)); } if (context is null) { throw new ArgumentNullException(nameof(context)); } return attribute.LookupMode switch { ServiceKeyLookupMode.ExplicitKey => ResolveKeyed(parameter, context, NormalizeKey(attribute.Key)), ServiceKeyLookupMode.InheritKey => ResolveKeyed(parameter, context, NormalizeKey(parentServiceKey)), _ => ResolveUnkeyed(parameter, context), }; } private static object? ResolveUnkeyed(ParameterInfo parameter, IComponentContext context) { if (context.TryResolve(parameter.ParameterType, out var instance)) { return instance; } return GetDefaultValueOrThrow(parameter, key: null); } private static object? ResolveKeyed(ParameterInfo parameter, IComponentContext context, object? key) { if (key is null) { return GetDefaultValueOrThrow(parameter, key); } if (context.TryResolveKeyed(key, parameter.ParameterType, out var instance)) { return instance; } return GetDefaultValueOrThrow(parameter, key); } private static object? GetDefaultValueOrThrow(ParameterInfo parameter, object? key) { if (parameter.HasDefaultValue) { return parameter.DefaultValue; } if (key is null) { throw new InvalidOperationException( string.Format( CultureInfo.CurrentCulture, "Unable to resolve service for type '{0}'.", parameter.ParameterType)); } throw new InvalidOperationException( string.Format( CultureInfo.CurrentCulture, "Unable to resolve service for type '{0}' using key '{1}'.", parameter.ParameterType, key)); } private static object? NormalizeKey(object? key) { if (key is null) { return null; } return ReferenceEquals(key, Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey) ? Autofac.Core.KeyedService.AnyKey : key; } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/FromKeyedServicesUsageCache.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Collections.Concurrent; using Autofac.Core; using Autofac.Core.Activators.Reflection; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// Caches lookups for usage on constructor parameters. /// [ExcludeFromCodeCoverage] internal static class FromKeyedServicesUsageCache { private static readonly FromKeyedServicesUsageReflectionCache ReflectionCache = new(); static FromKeyedServicesUsageCache() { ReflectionCacheSet.Shared.RegisterExternalCache(ReflectionCache); } /// /// Determines whether the resolve pipeline needs for the given activator. /// /// The reflection activator being inspected. /// when a constructor parameter uses ; otherwise . public static bool RequiresFromKeyedServicesMiddleware(ReflectionActivator activator) { if (activator is null) { throw new ArgumentNullException(nameof(activator)); } var constructorFinder = activator.ConstructorFinder; var cacheKey = new CacheKey(activator.LimitType, constructorFinder.GetType()); #if NETSTANDARD2_0 if (ReflectionCache.TryGet(cacheKey, out var cachedResult)) { return cachedResult; } var computed = ScanConstructors(constructorFinder, activator.LimitType); return ReflectionCache.GetOrAdd(cacheKey, computed); #else return ReflectionCache.GetOrAdd( cacheKey, static (_, state) => ScanConstructors(state.ConstructorFinder, state.LimitType), (ConstructorFinder: constructorFinder, activator.LimitType)); #endif } private static bool ScanConstructors(IConstructorFinder constructorFinder, Type limitType) { var constructors = constructorFinder.FindConstructors(limitType); foreach (var constructor in constructors) { foreach (var parameter in constructor.GetParameters()) { if (parameter.IsDefined(typeof(FromKeyedServicesAttribute), inherit: true)) { return true; } } } return false; } private readonly struct CacheKey : IEquatable { public CacheKey(Type implementationType, Type constructorFinderType) { ImplementationType = implementationType ?? throw new ArgumentNullException(nameof(implementationType)); ConstructorFinderType = constructorFinderType ?? throw new ArgumentNullException(nameof(constructorFinderType)); } private Type ImplementationType { get; } private Type ConstructorFinderType { get; } public bool Matches(ReflectionCacheClearPredicate clearPredicate) { var implementationAssemblies = new[] { ImplementationType.Assembly }; if (clearPredicate(ImplementationType, implementationAssemblies)) { return true; } var constructorFinderAssemblies = new[] { ConstructorFinderType.Assembly }; return clearPredicate(ConstructorFinderType, constructorFinderAssemblies); } public bool Equals(CacheKey other) { return ImplementationType == other.ImplementationType && ConstructorFinderType == other.ConstructorFinderType; } [ExcludeFromCodeCoverage] public override bool Equals(object? obj) { return obj is CacheKey other && Equals(other); } public override int GetHashCode() { unchecked { return (ImplementationType.GetHashCode() * 397) ^ ConstructorFinderType.GetHashCode(); } } } private sealed class FromKeyedServicesUsageReflectionCache : IReflectionCache { private readonly ConcurrentDictionary _cache = new(); public ReflectionCacheUsage Usage => ReflectionCacheUsage.Registration; public bool TryGet(CacheKey key, out bool result) { return _cache.TryGetValue(key, out result); } public bool GetOrAdd(CacheKey key, bool value) { return _cache.GetOrAdd(key, value); } public bool GetOrAdd(CacheKey key, Func valueFactory, (IConstructorFinder ConstructorFinder, Type LimitType) state) { #if NETSTANDARD2_0 return _cache.GetOrAdd(key, cacheKey => valueFactory(cacheKey, state)); #else return _cache.GetOrAdd(key, valueFactory, state); #endif } public void Clear() { _cache.Clear(); } public void Clear(ReflectionCacheClearPredicate clearPredicate) { if (clearPredicate is null) { throw new ArgumentNullException(nameof(clearPredicate)); } foreach (var key in _cache.Keys) { if (key.Matches(clearPredicate)) { _cache.TryRemove(key, out _); } } } } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/KeyTypeConversionException.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Globalization; namespace Autofac.Extensions.DependencyInjection; /// /// Exception indicating that type conversion failed when trying to inject a key /// using the /// . /// [ExcludeFromCodeCoverage] public class KeyTypeConversionException : Exception { /// /// Initializes a new instance of the class. /// /// /// The type of the key specified during service resolution. This is what /// would be injected into the constructor and needs to be converted. /// /// /// The type of parameter marked with the /// . /// This is what the key was trying to be converted to. /// public KeyTypeConversionException(Type resolutionKeyType, Type attributeKeyType) : this(resolutionKeyType, attributeKeyType, string.Format(CultureInfo.CurrentCulture, KeyTypeConversionExceptionResources.Message, resolutionKeyType, attributeKeyType)) { } /// /// Initializes a new instance of the class. /// /// /// The type of the key specified during service resolution. This is what /// would be injected into the constructor and needs to be converted. /// /// /// The type of parameter marked with the /// . /// This is what the key was trying to be converted to. /// /// /// A specific message for the exception to override the default. /// public KeyTypeConversionException(Type resolutionKeyType, Type attributeKeyType, string message) : base(message) { ResolutionKeyType = resolutionKeyType; AttributeKeyType = attributeKeyType; } /// /// Initializes a new instance of the class. /// /// /// The type of the key specified during service resolution. This is what /// would be injected into the constructor and needs to be converted. /// /// /// The type of parameter marked with the /// . /// This is what the key was trying to be converted to. /// /// The inner exception. public KeyTypeConversionException(Type resolutionKeyType, Type attributeKeyType, Exception? innerException) : this(resolutionKeyType, attributeKeyType, string.Format(CultureInfo.CurrentCulture, KeyTypeConversionExceptionResources.Message, resolutionKeyType, attributeKeyType), innerException) { } /// /// Initializes a new instance of the class. /// /// /// The type of the key specified during service resolution. This is what /// would be injected into the constructor and needs to be converted. /// /// /// The type of parameter marked with the /// . /// This is what the key was trying to be converted to. /// /// /// A specific message for the exception to override the default. /// /// The inner exception. public KeyTypeConversionException(Type resolutionKeyType, Type attributeKeyType, string message, Exception? innerException) : base(message, innerException) { ResolutionKeyType = resolutionKeyType; AttributeKeyType = attributeKeyType; } /// /// Gets the type of the parameter marked with the . /// /// /// The of parameter marked with the /// , /// which is the destination where the key should be injected. This should /// be compatible with the key provided during resolution. /// public Type AttributeKeyType { get; } /// /// Gets the type of the key specified during service resolution. /// /// /// The of key passed to the keyed service resolve /// operation. This is what would be injected as a constructor parameter to /// the service being resolved. /// public Type ResolutionKeyType { get; } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/KeyTypeConversionExceptionResources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Unable to convert key of type '{0}' to type '{1}' for parameter injection. ================================================ FILE: src/Autofac.Extensions.DependencyInjection/KeyTypeManipulation.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Collections.Concurrent; using System.ComponentModel; using System.Globalization; using System.Reflection; using Autofac.Core; namespace Autofac.Extensions.DependencyInjection; /// /// Utilities for converting keyed service key values into compatible types for /// injection using the . /// This logic originally came from Autofac.Configuration but there isn't a good /// "shared dependency" location for things like this other than core Autofac. /// internal class KeyTypeManipulation { private static readonly KeyTypeManipulationReflectionCache ReflectionCache = new(); static KeyTypeManipulation() { ReflectionCacheSet.Shared.RegisterExternalCache(ReflectionCache); } /// /// Converts an object to a type compatible with a given parameter. /// /// The object value to convert. /// The destination to which should be converted. /// The parameter for which the is being converted. /// /// An of type , converted using /// type converters specified on if available. If /// is then the output will be for reference /// types and the default value for value types. /// /// /// Thrown if conversion of the value fails. /// public static object? ChangeToCompatibleType(object? value, Type destinationType, ParameterInfo memberInfo) { TypeConverterAttribute? attrib = null; if (memberInfo != null) { attrib = ReflectionCache.GetOrAddParameterConverterAttribute(memberInfo); } return ChangeToCompatibleType(value, destinationType, attrib); } /// /// Converts an object to a type compatible with a given parameter. /// /// The object value to convert. /// The destination to which should be converted. /// The parameter for which the is being converted. /// /// An of type , converted using /// type converters specified on if available. If /// is then the output will be for reference /// types and the default value for value types. /// /// /// Thrown if conversion of the value fails. /// public static object? ChangeToCompatibleType(object? value, Type destinationType, MemberInfo memberInfo) { TypeConverterAttribute? attrib = null; if (memberInfo != null) { attrib = ReflectionCache.GetOrAddMemberConverterAttribute(memberInfo); } return ChangeToCompatibleType(value, destinationType, attrib); } /// /// Converts an object to a type compatible with a given parameter. /// /// The object value to convert. /// The destination to which should be converted. /// A , if available, specifying the type of converter to use. is being converted. /// /// An of type , converted using /// any type converters specified in if available. If /// is then the output will be for reference /// types and the default value for value types. /// /// /// Thrown if conversion of the value fails. /// public static object? ChangeToCompatibleType(object? value, Type destinationType, TypeConverterAttribute? converterAttribute = null) { if (destinationType == null) { throw new ArgumentNullException(nameof(destinationType)); } if (value == null) { return destinationType.GetTypeInfo().IsValueType ? ReflectionCache.GetOrAddDefaultValue(destinationType) : null; } // Try implicit conversion. if (destinationType.IsInstanceOfType(value)) { return value; } TypeConverter converter; // Try to get custom type converter information. if (converterAttribute != null && !string.IsNullOrEmpty(converterAttribute.ConverterTypeName)) { try { converter = GetTypeConverterFromName(converterAttribute.ConverterTypeName); } catch (InvalidOperationException ex) { throw new KeyTypeConversionException(value.GetType(), destinationType, ex); } if (converter.CanConvertFrom(value.GetType())) { return converter.ConvertFrom(null, CultureInfo.InvariantCulture, value); } } // If there's not a custom converter specified via attribute, try for a default. converter = TypeDescriptor.GetConverter(value.GetType()); if (converter.CanConvertTo(destinationType)) { return converter.ConvertTo(null, CultureInfo.InvariantCulture, value, destinationType); } // Try explicit opposite conversion. converter = TypeDescriptor.GetConverter(destinationType); if (converter.CanConvertFrom(value.GetType())) { return converter.ConvertFrom(null, CultureInfo.InvariantCulture, value); } // Try a TryParse method. if (value is string stringValue) { // Some types in later frameworks have string TryParse and ReadOnlySpan TryParse // so they result in an AmbiguousMatchException unless we specify. var parser = ReflectionCache.GetOrAddTryParseMethod(destinationType); if (parser != null) { var parameters = new object?[] { stringValue, null }; if ((bool)parser.Invoke(null, parameters)!) { return parameters[1]; } } } throw new KeyTypeConversionException(value.GetType(), destinationType); } /// /// Instantiates a type converter from its type name. /// /// /// The name of the of the . /// /// /// The instantiated . /// /// /// Thrown if does not correspond /// to a . /// private static TypeConverter GetTypeConverterFromName(string converterTypeName) { var converterType = ReflectionCache.GetOrAddConverterType(converterTypeName); return (TypeConverter)Activator.CreateInstance(converterType)!; } [ExcludeFromCodeCoverage] private sealed class KeyTypeManipulationReflectionCache : IReflectionCache { private readonly ConcurrentDictionary _parameterConverterAttributes = new(); private readonly ConcurrentDictionary _memberConverterAttributes = new(); private readonly ConcurrentDictionary _converterTypeCache = new(StringComparer.Ordinal); private readonly ConcurrentDictionary _tryParseMethodCache = new(); private readonly ConcurrentDictionary _defaultValueCache = new(); public ReflectionCacheUsage Usage => ReflectionCacheUsage.Resolution; public TypeConverterAttribute? GetOrAddParameterConverterAttribute(ParameterInfo parameter) { return _parameterConverterAttributes.GetOrAdd( parameter, static p => p.GetCustomAttributes(typeof(TypeConverterAttribute), true) .Cast() .FirstOrDefault()); } public TypeConverterAttribute? GetOrAddMemberConverterAttribute(MemberInfo member) { return _memberConverterAttributes.GetOrAdd( member, static m => m.GetCustomAttributes(typeof(TypeConverterAttribute), true) .Cast() .FirstOrDefault()); } public Type GetOrAddConverterType(string converterTypeName) { return _converterTypeCache.GetOrAdd( converterTypeName, static name => { var resolvedType = Type.GetType(name, true)!; if (!typeof(TypeConverter).GetTypeInfo().IsAssignableFrom(resolvedType.GetTypeInfo())) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, KeyTypeManipulationResources.TypeConverterAttributeTypeNotConverter, name)); } return resolvedType; }); } public MethodInfo? GetOrAddTryParseMethod(Type destinationType) { return _tryParseMethodCache.GetOrAdd( destinationType, static type => { var parameterTypes = new[] { typeof(string), type.MakeByRefType() }; return type.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Standard, parameterTypes, null); }); } public object? GetOrAddDefaultValue(Type destinationType) { return _defaultValueCache.GetOrAdd(destinationType, static t => Activator.CreateInstance(t)); } public void Clear() { _parameterConverterAttributes.Clear(); _memberConverterAttributes.Clear(); _converterTypeCache.Clear(); _tryParseMethodCache.Clear(); _defaultValueCache.Clear(); } public void Clear(ReflectionCacheClearPredicate clearPredicate) { if (clearPredicate is null) { throw new ArgumentNullException(nameof(clearPredicate)); } foreach (var parameter in _parameterConverterAttributes.Keys) { var member = parameter.Member; var assemblies = GetParameterAssemblies(parameter); if (clearPredicate(member, assemblies)) { _parameterConverterAttributes.TryRemove(parameter, out _); } } foreach (var member in _memberConverterAttributes.Keys) { if (clearPredicate(member, new[] { member.Module.Assembly })) { _memberConverterAttributes.TryRemove(member, out _); } } foreach (var type in _tryParseMethodCache.Keys) { if (clearPredicate(type, new[] { type.Assembly })) { _tryParseMethodCache.TryRemove(type, out _); } } foreach (var type in _defaultValueCache.Keys) { if (clearPredicate(type, new[] { type.Assembly })) { _defaultValueCache.TryRemove(type, out _); } } foreach (var entry in _converterTypeCache) { if (clearPredicate(entry.Value, new[] { entry.Value.Assembly })) { _converterTypeCache.TryRemove(entry.Key, out _); } } } private static IEnumerable GetParameterAssemblies(ParameterInfo parameter) { var memberAssembly = parameter.Member.Module.Assembly; var parameterAssembly = parameter.ParameterType.Assembly; if (ReferenceEquals(memberAssembly, parameterAssembly)) { yield return memberAssembly; yield break; } yield return memberAssembly; yield return parameterAssembly; } } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/KeyTypeManipulationResources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Unable to convert object of type '{0}' to type '{1}'. The type '{0}' specified in the TypeConverterAttribute is not a TypeConverter. ================================================ FILE: src/Autofac.Extensions.DependencyInjection/KeyedServiceMiddleware.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Collections.Concurrent; using System.Reflection; using Autofac.Core; using Autofac.Core.Resolving.Pipeline; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// Middleware that supports keyed service compatibility. /// internal class KeyedServiceMiddleware : IResolveMiddleware { private readonly bool _addFromKeyedServiceParameter; /// /// Initializes a new instance of the class. /// /// Whether or not the from-keyed-service parameter should be added. public KeyedServiceMiddleware(bool addFromKeyedServiceParameter) { _addFromKeyedServiceParameter = addFromKeyedServiceParameter; } /// /// Gets a single instance of this middleware that does not add the keyed services parameter. /// public static KeyedServiceMiddleware InstanceWithoutFromKeyedServicesParameter { get; } = new(addFromKeyedServiceParameter: false); /// /// Gets a single instance of this middleware that adds the keyed services parameter. /// public static KeyedServiceMiddleware InstanceWithFromKeyedServicesParameter { get; } = new(addFromKeyedServiceParameter: true); /// public PipelinePhase Phase => PipelinePhase.Activation; /// public void Execute(ResolveRequestContext context, Action next) { Parameter? microsoftServiceKeyParameter = null; Parameter? fromKeyedServicesParameter = null; var keyedService = context.Service as Autofac.Core.KeyedService; object? inheritedServiceKey = null; if (keyedService is not null) { if (Autofac.Core.KeyedService.IsAnyKey(keyedService.ServiceKey)) { context.Parameters.TryGetKeyedServiceKey(out inheritedServiceKey); } else { inheritedServiceKey = keyedService.ServiceKey; } } var effectiveServiceKey = inheritedServiceKey; if (keyedService is not null && effectiveServiceKey is not null && !Autofac.Core.KeyedService.IsAnyKey(effectiveServiceKey)) { microsoftServiceKeyParameter = new MicrosoftServiceKeyParameter(effectiveServiceKey); } if (_addFromKeyedServiceParameter) { // [FromKeyedServices("key")] - Specifies a keyed service // for injection into a constructor. This is similar to the // Autofac [KeyFilter] attribute. fromKeyedServicesParameter = new FromKeyedServicesParameter(inheritedServiceKey); } if (microsoftServiceKeyParameter is not null || fromKeyedServicesParameter is not null) { context.ChangeParameters(AppendParameters(context.Parameters, microsoftServiceKeyParameter, fromKeyedServicesParameter)); } next(context); } private static List AppendParameters(IEnumerable original, Parameter? first, Parameter? second) { // Build a concrete list rather than using yield return, which would // allocate a compiler-generated state machine on every call. var list = new List(original is ICollection col ? col.Count + 2 : 4); list.AddRange(original); if (first is not null) { list.Add(first); } if (second is not null) { list.Add(second); } return list; } /// /// Caches the presence of relevant attributes on parameters to avoid repeated reflection calls. /// private static class ParameterAttributeCache { private static readonly ParameterAttributeReflectionCache ReflectionCache = new(); static ParameterAttributeCache() { ReflectionCacheSet.Shared.RegisterExternalCache(ReflectionCache); } /// /// Determines whether the parameter has the defined. /// /// The parameter to check. /// /// if the parameter has the attribute; otherwise, . /// public static bool HasMicrosoftServiceKey(ParameterInfo parameter) { return ReflectionCache.GetOrAddMicrosoftServiceKeyAttributePresence(parameter); } /// /// Gets the defined on the parameter, if any. /// /// The parameter to check. /// /// The if defined; otherwise, . /// public static FromKeyedServicesAttribute? GetFromKeyedServicesAttribute(ParameterInfo parameter) { return ReflectionCache.GetOrAddFromKeyedServicesAttribute(parameter); } [ExcludeFromCodeCoverage] private sealed class ParameterAttributeReflectionCache : IReflectionCache { private readonly ConcurrentDictionary _microsoftServiceKeyAttributePresence = new(); private readonly ConcurrentDictionary _fromKeyedServicesAttributes = new(); public ReflectionCacheUsage Usage => ReflectionCacheUsage.Resolution; public bool GetOrAddMicrosoftServiceKeyAttributePresence(ParameterInfo parameter) { return _microsoftServiceKeyAttributePresence.GetOrAdd( parameter, static p => Attribute.IsDefined(p, typeof(Microsoft.Extensions.DependencyInjection.ServiceKeyAttribute), inherit: true)); } public FromKeyedServicesAttribute? GetOrAddFromKeyedServicesAttribute(ParameterInfo parameter) { return _fromKeyedServicesAttributes.GetOrAdd( parameter, static p => p.GetCustomAttribute(inherit: true)); } public void Clear() { _microsoftServiceKeyAttributePresence.Clear(); _fromKeyedServicesAttributes.Clear(); } public void Clear(ReflectionCacheClearPredicate clearPredicate) { if (clearPredicate is null) { throw new ArgumentNullException(nameof(clearPredicate)); } foreach (var parameter in _microsoftServiceKeyAttributePresence.Keys) { if (Matches(clearPredicate, parameter)) { _microsoftServiceKeyAttributePresence.TryRemove(parameter, out _); } } foreach (var parameter in _fromKeyedServicesAttributes.Keys) { if (Matches(clearPredicate, parameter)) { _fromKeyedServicesAttributes.TryRemove(parameter, out _); } } } private static bool Matches(ReflectionCacheClearPredicate clearPredicate, ParameterInfo parameter) { var member = parameter.Member; var memberAssembly = member.Module.Assembly; var parameterAssembly = parameter.ParameterType.Assembly; if (ReferenceEquals(memberAssembly, parameterAssembly)) { return clearPredicate(member, new[] { memberAssembly }); } return clearPredicate(member, new[] { memberAssembly, parameterAssembly }); } } } /// /// A that supplies the service key for parameters /// marked with . /// Uses a field instead of a closure to avoid delegate/closure allocations. /// private sealed class MicrosoftServiceKeyParameter : Parameter { private readonly object _serviceKey; public MicrosoftServiceKeyParameter(object serviceKey) { _serviceKey = serviceKey; } public override bool CanSupplyValue(ParameterInfo pi, IComponentContext context, [NotNullWhen(true)] out Func? valueProvider) { if (ParameterAttributeCache.HasMicrosoftServiceKey(pi)) { var key = _serviceKey; valueProvider = () => KeyTypeManipulation.ChangeToCompatibleType(key, pi.ParameterType, pi); return true; } valueProvider = null; return false; } } /// /// A that supplies keyed service dependencies for parameters /// marked with . /// Uses a field instead of a closure to avoid delegate/closure allocations. /// private sealed class FromKeyedServicesParameter : Parameter { private readonly object? _requestedServiceKey; public FromKeyedServicesParameter(object? requestedServiceKey) { _requestedServiceKey = requestedServiceKey; } public override bool CanSupplyValue(ParameterInfo pi, IComponentContext context, [NotNullWhen(true)] out Func? valueProvider) { var filter = ParameterAttributeCache.GetFromKeyedServicesAttribute(pi); if (filter is not null) { var key = _requestedServiceKey; valueProvider = () => filter.ResolveParameter(pi, context, key); return true; } valueProvider = null; return false; } } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/Polyfills/NotNullWhenAttribute.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. #if NETSTANDARD2_0 namespace System.Diagnostics.CodeAnalysis; /// /// Polyfill for which is not available in netstandard2.0. /// Specifies that when a method returns , /// the parameter will not be null even if the corresponding type allows it. /// [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class NotNullWhenAttribute : Attribute { /// /// Initializes a new instance of the class. /// /// /// The return value condition. If the method returns this value, the associated parameter will not be null. /// public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; /// /// Gets a value indicating whether the return value should be true or false for the parameter to be non-null. /// public bool ReturnValue { get; } } #endif ================================================ FILE: src/Autofac.Extensions.DependencyInjection/Properties/AssemblyInfo.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Autofac.Extensions.DependencyInjection.Test, PublicKey=00240000048000009400000006020000002400005253413100040000010001008728425885ef385e049261b18878327dfaaf0d666dea3bd2b0e4f18b33929ad4e5fbc9087e7eda3c1291d2de579206d9b4292456abffbe8be6c7060b36da0c33b883e3878eaf7c89fddf29e6e27d24588e81e86f3a22dd7b1a296b5f06fbfb500bbd7410faa7213ef4e2ce7622aefc03169b0324bcd30ccfe9ac8204e4960be6")] [assembly: CLSCompliant(false)] ================================================ FILE: src/Autofac.Extensions.DependencyInjection/ServiceCollectionExtensions.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// Extension methods on to register the . /// public static class ServiceCollectionExtensions { /// /// Adds the to the service collection. ONLY FOR PRE-ASP.NET 3.0 HOSTING. THIS WON'T WORK /// FOR ASP.NET CORE 3.0+ OR GENERIC HOSTING. /// /// The service collection to add the factory to. /// Action on a that adds component registrations to the container. /// The service collection. public static IServiceCollection AddAutofac(this IServiceCollection services, Action? configurationAction = null) { return services.AddSingleton>(new AutofacServiceProviderFactory(configurationAction)); } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/ServiceDescriptorExtensions.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection; /// /// Extensions for working with . /// internal static class ServiceDescriptorExtensions { /// /// Normalizes the implementation instance data between keyed and not keyed services. /// /// /// The to normalize. /// /// /// The appropriate implementation instance from the service descriptor. /// public static object? NormalizedImplementationInstance(this ServiceDescriptor descriptor) => descriptor.IsKeyedService ? descriptor.KeyedImplementationInstance : descriptor.ImplementationInstance; /// /// Normalizes the implementation type data between keyed and not keyed services. /// /// /// The to normalize. /// /// /// The appropriate implementation type from the service descriptor. /// public static Type? NormalizedImplementationType(this ServiceDescriptor descriptor) => descriptor.IsKeyedService ? descriptor.KeyedImplementationType : descriptor.ImplementationType; } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/ServiceProviderExtensions.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Globalization; namespace Autofac.Extensions.DependencyInjection; /// /// Extension methods for use with the . /// public static class ServiceProviderExtensions { /// /// Tries to cast the instance of from when possible. /// /// The instance of . /// Throws an when instance of can't be assigned to . /// Returns the instance of exposed by . public static ILifetimeScope GetAutofacRoot(this IServiceProvider serviceProvider) { if (serviceProvider is not AutofacServiceProvider autofacServiceProvider) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ServiceProviderExtensionsResources.WrongProviderType, serviceProvider?.GetType())); } return autofacServiceProvider.LifetimeScope; } } ================================================ FILE: src/Autofac.Extensions.DependencyInjection/ServiceProviderExtensionsResources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Unable to retrieve Autofac root lifetime scope from service provider of type {0}. ================================================ FILE: src/Autofac.Extensions.DependencyInjection/TypeExtensions.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Collections.Concurrent; using Autofac.Core; namespace Autofac.Extensions.DependencyInjection; /// /// Extensions for working with types. /// internal static class TypeExtensions { private static readonly TypeExtensionsReflectionCache ReflectionCache = new(); static TypeExtensions() { ReflectionCacheSet.Shared.RegisterExternalCache(ReflectionCache); } /// /// Checks a type to determine if it is some kind of collection or enumerable. /// /// /// The type to check. /// /// if the type is a collection or enumerable; otherwise, . internal static bool IsCollection(this Type serviceType) { return ReflectionCache.GetOrAddCollectionType( serviceType, static type => { if (type.IsArray) { return true; } if (!type.IsGenericType) { return false; } return IsGenericTypeDefinedBy(type, typeof(IEnumerable<>)) || IsGenericListOrCollectionInterfaceType(type); }); } private static bool IsGenericTypeDefinedBy(Type type, Type openGeneric) { return !type.ContainsGenericParameters && type.IsGenericType && type.GetGenericTypeDefinition() == openGeneric; } private static bool IsGenericListOrCollectionInterfaceType(Type type) { return IsGenericTypeDefinedBy(type, typeof(IList<>)) || IsGenericTypeDefinedBy(type, typeof(ICollection<>)) || IsGenericTypeDefinedBy(type, typeof(IReadOnlyCollection<>)) || IsGenericTypeDefinedBy(type, typeof(IReadOnlyList<>)); } [ExcludeFromCodeCoverage] private sealed class TypeExtensionsReflectionCache : IReflectionCache { private readonly ConcurrentDictionary _collectionTypeCache = new(); public ReflectionCacheUsage Usage => ReflectionCacheUsage.Resolution; public bool GetOrAddCollectionType(Type serviceType, Func valueFactory) { return _collectionTypeCache.GetOrAdd(serviceType, valueFactory); } public void Clear() { _collectionTypeCache.Clear(); } public void Clear(ReflectionCacheClearPredicate clearPredicate) { if (clearPredicate is null) { throw new ArgumentNullException(nameof(clearPredicate)); } foreach (var type in _collectionTypeCache.Keys) { if (clearPredicate(type, new[] { type.Assembly })) { _collectionTypeCache.TryRemove(type, out _); } } } } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Integration.Test/Autofac.Extensions.DependencyInjection.Integration.Test.csproj ================================================  net10.0;net8.0 $(NoWarn);CS1591 true ../../Autofac.snk true true ../../build/Test.ruleset AllEnabledByDefault true false latest enable all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Integration.Test/IntegrationTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.AspNetCore.Mvc.Testing; using Xunit; #if NET10_0 using Integration.Net10; #endif #if NET8_0 using Integration.Net8; #endif namespace Autofac.Extensions.DependencyInjection.Integration.Test; public class IntegrationTests : IClassFixture> { public IntegrationTests(WebApplicationFactory appFactory) { AppFactory = appFactory; } public WebApplicationFactory AppFactory { get; } [Fact] public async Task GetDate() { var client = AppFactory.CreateClient(); var response = await client.GetAsync(new Uri("/Date", UriKind.Relative)); response.EnsureSuccessStatusCode(); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Integration.Test/Properties/AssemblyInfo.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. [assembly: CLSCompliant(false)] ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Assertions.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Autofac.Core; namespace Autofac.Extensions.DependencyInjection.Test; internal static class Assertions { public static void AssertRegistered(this IComponentContext context) { Assert.True(context.IsRegistered()); } public static void AssertNotRegistered(this IComponentContext context) { Assert.False(context.IsRegistered()); } public static void AssertImplementation(this IComponentContext context) { var service = context.Resolve(); Assert.IsAssignableFrom(service); } public static void AssertSharing(this IComponentContext context, InstanceSharing sharing) { var cr = context.RegistrationFor(); Assert.Equal(sharing, cr.Sharing); } public static void AssertLifetime(this IComponentContext context) { var cr = context.RegistrationFor(); Assert.IsType(cr.Lifetime); } public static void AssertOwnership(this IComponentContext context, InstanceOwnership ownership) { var cr = context.RegistrationFor(); Assert.Equal(ownership, cr.Ownership); } public static IComponentRegistration RegistrationFor(this IComponentContext context) { Assert.True(context.ComponentRegistry.TryGetRegistration(new TypedService(typeof(TService)), out IComponentRegistration r)); return r; } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Autofac.Extensions.DependencyInjection.Test.csproj ================================================  net10.0;net8.0 $(NoWarn);CS1591 true ../../Autofac.snk true true ../../build/Test.ruleset AllEnabledByDefault true false latest enable all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/AutofacChildLifetimeScopeConfigurationAdapterTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Autofac.Extensions.DependencyInjection.Test; public sealed class AutofacChildLifetimeScopeConfigurationAdapterTests { [Fact] public void AddMultipleConfigurationContainsConfigurations() { var adapter = new AutofacChildLifetimeScopeConfigurationAdapter(); adapter.Add(builder => { }); adapter.Add(builder => { }); Assert.Equal(2, adapter.ConfigurationActions.Count); } [Fact] public void AddNullConfigurationThrows() => Assert.Throws(() => new AutofacChildLifetimeScopeConfigurationAdapter().Add(null)); } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/AutofacChildLifetimeScopeServiceProviderFactoryTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test; public sealed class AutofacChildLifetimeScopeServiceProviderFactoryTests { [Fact] public void CreateBuilderReturnsNewInstance() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScope); var configurationAdapter = factory.CreateBuilder(new ServiceCollection()); Assert.NotNull(configurationAdapter); } [Fact] public void CreateBuilderExecutesConfigurationActionWhenProvided() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScope, b => b.Register(c => "Foo")); var configurationAdapter = factory.CreateBuilder(new ServiceCollection()); var builder = new ContainerBuilder(); foreach (var action in configurationAdapter.ConfigurationActions) { action(builder); } Assert.Equal("Foo", builder.Build().Resolve()); } [Fact] public void CreateBuilderAllowsForNullConfigurationAction() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScope); var configurationAdapter = factory.CreateBuilder(new ServiceCollection()); Assert.NotNull(configurationAdapter); } [Fact] public void CreateBuilderReturnsInstanceWithServicesPopulated() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScope); var services = new ServiceCollection().AddTransient(); var configurationAdapter = factory.CreateBuilder(services); var builder = new ContainerBuilder(); foreach (var action in configurationAdapter.ConfigurationActions) { action(builder); } Assert.True(builder.Build().IsRegistered()); } [Fact] public void CreateServiceProviderBuildsServiceProviderUsingAdapter() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScope); var services = new ServiceCollection().AddTransient(); var configurationAdapter = factory.CreateBuilder(services); var serviceProvider = factory.CreateServiceProvider(configurationAdapter); Assert.NotNull(serviceProvider.GetService(typeof(object))); } [Fact] public void CreateServiceProviderThrowsWhenProvidedNullAdapter() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScope); var exception = Assert.Throws(() => factory.CreateServiceProvider(null)); Assert.Equal("containerBuilder", exception.ParamName); } [Fact] public void CreateServiceProviderReturnsAutofacServiceProvider() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScope); var serviceProvider = factory.CreateServiceProvider(new AutofacChildLifetimeScopeConfigurationAdapter()); Assert.IsType(serviceProvider); } [Fact] public void CreateServiceProviderAddDepToServiceCollectionAndAddConfigurationTypesResolvable() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScope); var services = new ServiceCollection().AddTransient(); var configurationAdapter = factory.CreateBuilder(services); configurationAdapter.Add(builder => builder.RegisterType()); var serviceProvider = factory.CreateServiceProvider(configurationAdapter); serviceProvider.GetRequiredService(); serviceProvider.GetRequiredService(); } [Fact] public void CreateServiceProviderAddDepToRootContainerResolvable() { var factory = new AutofacChildLifetimeScopeServiceProviderFactory(GetRootLifetimeScopeWithDependency(typeof(DependencyOne))); var configurationAdapter = factory.CreateBuilder(new ServiceCollection()); var serviceProvider = factory.CreateServiceProvider(configurationAdapter); serviceProvider.GetRequiredService(); } [Fact] public void Ctor_NullRootAccessor() { Assert.Throws(() => new AutofacChildLifetimeScopeServiceProviderFactory((Func)null!)); } [Fact] public void Ctor_NullRootScope() { Assert.Throws(() => new AutofacChildLifetimeScopeServiceProviderFactory((ILifetimeScope)null!)); } private static ILifetimeScope GetRootLifetimeScope() => new ContainerBuilder().Build(); private static ILifetimeScope GetRootLifetimeScopeWithDependency(Type type) { var containerBuilder = new ContainerBuilder(); containerBuilder .RegisterType(type) .As(); return containerBuilder.Build(); } [SuppressMessage("CA1812", "CA1812", Justification = "Instantiated via dependency injection.")] private class DependencyOne { } [SuppressMessage("CA1812", "CA1812", Justification = "Instantiated via dependency injection.")] private class DependencyTwo { } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/AutofacRegistrationTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Diagnostics.CodeAnalysis; using Autofac.Core; using Autofac.Core.Lifetime; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace Autofac.Extensions.DependencyInjection.Test; public class AutofacRegistrationTests { [Fact] public void PopulateRegistersServiceProvider() { var builder = new ContainerBuilder(); builder.Populate(Enumerable.Empty()); var container = builder.Build(); container.AssertRegistered(); } [Fact] public void PopulateThrowsForNullBuilder() { Assert.Throws(() => AutofacRegistration.Populate(null, Enumerable.Empty())); } [Fact] public void PopulateThrowsForNullDescriptors() { Assert.Throws(() => new ContainerBuilder().Populate(null)); } [Fact] public void CorrectServiceProviderIsRegistered() { var builder = new ContainerBuilder(); builder.Populate(Enumerable.Empty()); var container = builder.Build(); container.AssertImplementation(); } [Fact] public void ServiceProviderInstancesAreNotTracked() { var builder = new ContainerBuilder(); builder.Populate(Enumerable.Empty()); var container = builder.Build(); container.AssertOwnership(InstanceOwnership.ExternallyOwned); } [Fact] public void PopulateRegistersServiceScopeFactory() { var builder = new ContainerBuilder(); builder.Populate(Enumerable.Empty()); var container = builder.Build(); container.AssertRegistered(); } [Fact] public void ServiceScopeFactoryIsRegistered() { var builder = new ContainerBuilder(); builder.Populate(Enumerable.Empty()); var container = builder.Build(); container.AssertImplementation(); } [Fact] public void CanRegisterTransientService() { var builder = new ContainerBuilder(); var descriptor = new ServiceDescriptor(typeof(IService), typeof(Service), ServiceLifetime.Transient); builder.Populate(new ServiceDescriptor[] { descriptor }); var container = builder.Build(); container.AssertLifetime(); container.AssertSharing(InstanceSharing.None); container.AssertOwnership(InstanceOwnership.OwnedByLifetimeScope); } [Fact] public void CanRegisterSingletonService() { var builder = new ContainerBuilder(); var descriptor = new ServiceDescriptor(typeof(IService), typeof(Service), ServiceLifetime.Singleton); builder.Populate(new ServiceDescriptor[] { descriptor }); var container = builder.Build(); container.AssertLifetime(); container.AssertSharing(InstanceSharing.Shared); container.AssertOwnership(InstanceOwnership.OwnedByLifetimeScope); } [Fact] public void CanRebaseSingletonServiceToNamedLifetimeScope() { var builder = new ContainerBuilder(); var descriptor = new ServiceDescriptor(typeof(IService), typeof(Service), ServiceLifetime.Singleton); builder.Populate(new ServiceDescriptor[] { descriptor }, "MY_SCOPE"); var container = builder.Build(); container.AssertLifetime(); container.AssertSharing(InstanceSharing.Shared); container.AssertOwnership(InstanceOwnership.OwnedByLifetimeScope); } [Fact] public void CanRegisterScopedService() { var builder = new ContainerBuilder(); var descriptor = new ServiceDescriptor(typeof(IService), typeof(Service), ServiceLifetime.Scoped); builder.Populate(new ServiceDescriptor[] { descriptor }); var container = builder.Build(); container.AssertLifetime(); container.AssertSharing(InstanceSharing.Shared); container.AssertOwnership(InstanceOwnership.OwnedByLifetimeScope); } [Fact] public void CanRegisterGenericService() { var builder = new ContainerBuilder(); var descriptor = new ServiceDescriptor(typeof(IList<>), typeof(List<>), ServiceLifetime.Scoped); builder.Populate(new ServiceDescriptor[] { descriptor }); var container = builder.Build(); container.AssertRegistered>(); } [Fact] public void CanRegisterFactoryService() { var builder = new ContainerBuilder(); var descriptor = new ServiceDescriptor(typeof(IService), sp => new Service(), ServiceLifetime.Transient); builder.Populate(new ServiceDescriptor[] { descriptor }); var container = builder.Build(); container.AssertRegistered>(); } [Fact] public void CanResolveOptionsFromChildScopeProvider() { // Issue #32: Registering options in a child scope fails to resolve IOptions. var container = new ContainerBuilder().Build(); var scope = container.BeginLifetimeScope(b => { var services = new ServiceCollection(); services .AddOptions() .Configure(opt => { opt.Value = 6; }); b.Populate(services); }); using var provider = new AutofacServiceProvider(scope); var options = provider.GetRequiredService>(); Assert.Equal(6, options.Value.Value); } [Fact] public void CanGenerateFactoryService() { var builder = new ContainerBuilder(); var descriptor = new ServiceDescriptor(typeof(IService), typeof(Service), ServiceLifetime.Transient); builder.Populate(new ServiceDescriptor[] { descriptor }); var container = builder.Build(); container.AssertRegistered>(); } [Fact] public void ServiceCollectionConfigurationIsRetainedInRootContainer() { var collection = new ServiceCollection(); collection.AddOptions(); collection.Configure(options => { options.Value = 5; }); var builder = new ContainerBuilder(); builder.Populate(collection); var container = builder.Build(); var resolved = container.Resolve>(); Assert.NotNull(resolved.Value); Assert.Equal(5, resolved.Value.Value); } [Fact] public void RegistrationsAddedAfterPopulateComeLastWhenResolvedWithIEnumerable() { const string s1 = "s1"; const string s2 = "s2"; const string s3 = "s3"; const string s4 = "s4"; var collection = new ServiceCollection(); collection.AddTransient(provider => s1); collection.AddTransient(provider => s2); var builder = new ContainerBuilder(); builder.Populate(collection); builder.Register(c => s3); builder.Register(c => s4); var container = builder.Build(); var resolved = container.Resolve>().ToArray(); Assert.Equal(resolved, new[] { s1, s2, s3, s4 }); } [Fact] public void RegistrationsAddedBeforePopulateComeFirstWhenResolvedWithIEnumerable() { const string s1 = "s1"; const string s2 = "s2"; const string s3 = "s3"; const string s4 = "s4"; var builder = new ContainerBuilder(); builder.Register(c => s1); builder.Register(c => s2); var collection = new ServiceCollection(); collection.AddTransient(provider => s3); collection.AddTransient(provider => s4); builder.Populate(collection); var container = builder.Build(); var resolved = container.Resolve>().ToArray(); Assert.Equal(resolved, new[] { s1, s2, s3, s4 }); } private class Service : IService { } private interface IService { } [SuppressMessage("CA1812", "CA1812", Justification = "Instantiated via dependency injection.")] private class TestOptions { public int Value { get; set; } } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/AutofacServiceProviderFactoryTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Autofac.Builder; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test; public class AutofacServiceProviderFactoryTests { [Fact] public void CreateBuilderReturnsNewInstance() { var factory = new AutofacServiceProviderFactory(); var builder = factory.CreateBuilder(new ServiceCollection()); Assert.NotNull(builder); } [Fact] public void CreateBuilderExecutesConfigurationActionWhenProvided() { var factory = new AutofacServiceProviderFactory(config => config.Register(c => "Foo")); var builder = factory.CreateBuilder(new ServiceCollection()); Assert.Equal("Foo", builder.Build().Resolve()); } [Fact] public void CreateBuilderAllowsForNullConfigurationAction() { var factory = new AutofacServiceProviderFactory(); var builder = factory.CreateBuilder(new ServiceCollection()); Assert.NotNull(builder); } [Fact] public void CreateBuilderReturnsInstanceWithServicesPopulated() { var factory = new AutofacServiceProviderFactory(); var services = new ServiceCollection(); services.AddTransient(); var builder = factory.CreateBuilder(services); Assert.True(builder.Build().IsRegistered()); } [Fact] public void CreateServiceProviderBuildsServiceProviderUsingContainerBuilder() { var factory = new AutofacServiceProviderFactory(); var services = new ServiceCollection().AddTransient(); var builder = factory.CreateBuilder(services); var serviceProvider = factory.CreateServiceProvider(builder); Assert.NotNull(serviceProvider.GetService(typeof(object))); } [Fact] public void CreateServiceProviderThrowsWhenProvidedNullContainerBuilder() { var factory = new AutofacServiceProviderFactory(); var exception = Assert.Throws(() => factory.CreateServiceProvider(null)); Assert.Equal("containerBuilder", exception.ParamName); } [Fact] public void CreateServiceProviderReturnsAutofacServiceProvider() { var factory = new AutofacServiceProviderFactory(); var serviceProvider = factory.CreateServiceProvider(new ContainerBuilder()); Assert.IsType(serviceProvider); } [Fact] public void CreateServiceProviderUsesDefaultContainerBuildOptionsWhenNotProvided() { var factory = new AutofacServiceProviderFactory(); var services = new ServiceCollection().AddSingleton("Foo"); var builder = factory.CreateBuilder(services); var serviceProvider = factory.CreateServiceProvider(builder); Assert.NotNull(serviceProvider.GetService>()); } [Fact] public void CreateServiceProviderUsesContainerBuildOptionsWhenProvided() { var options = ContainerBuildOptions.ExcludeDefaultModules; var factory = new AutofacServiceProviderFactory(options); var services = new ServiceCollection().AddSingleton("Foo"); var builder = factory.CreateBuilder(services); var serviceProvider = factory.CreateServiceProvider(builder); Assert.Null(serviceProvider.GetService>()); } [Fact] public void CanProvideContainerBuildOptionsAndConfigurationAction() { var factory = new AutofacServiceProviderFactory( ContainerBuildOptions.ExcludeDefaultModules, config => config.Register(c => "Foo")); var builder = factory.CreateBuilder(new ServiceCollection()); var serviceProvider = factory.CreateServiceProvider(builder); Assert.NotNull(serviceProvider.GetService()); Assert.Null(serviceProvider.GetService>()); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/AutofacServiceProviderTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Autofac.Builder; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test; // Most of the functionality is verified via the specification tests. These are some extras for error handling, etc. public class AutofacServiceProviderTests { [Fact] public void Ctor_NullLifetimeScope() { Assert.Throws(() => new AutofacServiceProvider(null!)); } [Fact] public void GetKeyedService_NullServiceType() { using var provider = new AutofacServiceProvider(new ContainerBuilder().Build()); Assert.Throws(() => provider.GetKeyedService(null!, "key")); } [Fact] public void GetRequiredKeyedService_NullServiceType() { using var provider = new AutofacServiceProvider(new ContainerBuilder().Build()); Assert.Throws(() => provider.GetRequiredKeyedService(null!, "key")); } [Fact] public void GetRequiredService_DependencyResolutionFails() { var builder = new ContainerBuilder(); using var provider = new AutofacServiceProvider(builder.Build()); Assert.Throws(() => provider.GetRequiredService()); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/FromKeyedServicesAttributeExtensionsTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Reflection; using Autofac.Core; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test; public class FromKeyedServicesAttributeExtensionsTests { [Fact] public void ResolveParameterExplicitKey() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.Explicit)); var parameter = GetParameter(nameof(ParameterTargets.Explicit)); var value = attribute.ResolveParameter(parameter, container, parentServiceKey: "parent"); Assert.IsType(value); } [Fact] public void ResolveParameterInheritedAnyKeyUsedForCollection() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.InheritedCollection)); var parameter = GetParameter(nameof(ParameterTargets.InheritedCollection)); var value = attribute.ResolveParameter(parameter, container, parentServiceKey: Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey); var services = Assert.IsAssignableFrom>(value); Assert.NotEmpty(services); } [Fact] public void ResolveParameterInheritedAnyKeyUsedForNonCollection() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.Inherited)); var parameter = GetParameter(nameof(ParameterTargets.Inherited)); Assert.Throws(() => attribute.ResolveParameter(parameter, container, parentServiceKey: Microsoft.Extensions.DependencyInjection.KeyedService.AnyKey)); } [Fact] public void ResolveParameterInheritedKey() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.Inherited)); var parameter = GetParameter(nameof(ParameterTargets.Inherited)); var value = attribute.ResolveParameter(parameter, container, parentServiceKey: "inherited"); Assert.IsType(value); } [Fact] public void ResolveParameterInheritedKeyIsNull() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.InheritedWithDefault)); var parameter = GetParameter(nameof(ParameterTargets.InheritedWithDefault)); var value = attribute.ResolveParameter(parameter, container, parentServiceKey: null); Assert.Equal("fallback", value); } [Fact] public void ResolveParameterKeyedServiceMissingAndNoDefault() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.ExplicitMissingNoDefault)); var parameter = GetParameter(nameof(ParameterTargets.ExplicitMissingNoDefault)); var ex = Assert.Throws(() => attribute.ResolveParameter(parameter, container, parentServiceKey: "missing")); Assert.Contains("using key", ex.Message, StringComparison.Ordinal); } [Fact] public void ResolveParameterNullAttribute() { using var container = BuildContainer(); var parameter = GetParameter(nameof(ParameterTargets.Explicit)); var ex = Assert.Throws(() => FromKeyedServicesAttributeExtensions.ResolveParameter(null!, parameter, container, parentServiceKey: null)); Assert.Equal("attribute", ex.ParamName); } [Fact] public void ResolveParameterNullContext() { var attribute = GetAttribute(nameof(ParameterTargets.Explicit)); var parameter = GetParameter(nameof(ParameterTargets.Explicit)); var ex = Assert.Throws(() => attribute.ResolveParameter(parameter, null!, parentServiceKey: null)); Assert.Equal("context", ex.ParamName); } [Fact] public void ResolveParameterNullParameter() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.Explicit)); var ex = Assert.Throws(() => attribute.ResolveParameter(null!, container, parentServiceKey: null)); Assert.Equal("parameter", ex.ParamName); } [Fact] public void ResolveParameterResolveFails() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.ExplicitWithDefault)); var parameter = GetParameter(nameof(ParameterTargets.ExplicitWithDefault)); var value = attribute.ResolveParameter(parameter, container, parentServiceKey: null); Assert.Equal("fallback", value); } [Fact] public void ResolveParameterUnkeyedServiceMissingAndNoDefault() { using var container = BuildContainer(); var attribute = GetAttribute(nameof(ParameterTargets.NullKeyNoDefault)); var parameter = GetParameter(nameof(ParameterTargets.NullKeyNoDefault)); var ex = Assert.Throws(() => attribute.ResolveParameter(parameter, container, parentServiceKey: null)); Assert.Contains("Unable to resolve service for type", ex.Message, StringComparison.Ordinal); Assert.DoesNotContain("using key", ex.Message, StringComparison.Ordinal); } private static IContainer BuildContainer() { var builder = new ContainerBuilder(); builder.RegisterType().Keyed("explicit"); builder.RegisterType().Keyed("inherited"); return builder.Build(); } private static FromKeyedServicesAttribute GetAttribute(string methodName) { return GetParameter(methodName).GetCustomAttribute()!; } private static ParameterInfo GetParameter(string methodName) { return typeof(ParameterTargets).GetMethod(methodName)!.GetParameters()[0]; } private interface IService { } private sealed class KeyedService : IService { } private sealed class InheritedKeyedService : IService { } private sealed class ParameterTargets { public void Explicit([FromKeyedServices("explicit")] IService service) { } public void Inherited([FromKeyedServices] IService service) { } public void InheritedCollection([FromKeyedServices] IEnumerable service) { } public void InheritedWithDefault([FromKeyedServices] string service = "fallback") { } public void ExplicitWithDefault([FromKeyedServices("missing")] string service = "fallback") { } public void ExplicitMissingNoDefault([FromKeyedServices("missing")] IService service) { } public void NullKeyNoDefault([FromKeyedServices(null)] string service) { } } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/FromKeyedServicesUsageCacheTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Autofac.Core; using Autofac.Core.Activators.Reflection; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test; public class FromKeyedServicesUsageCacheTests { [Fact] public void RequiresFromKeyedServicesMiddlewareAttributeNotUsed() { var activator = GetReflectionActivator(); var needsMiddleware = FromKeyedServicesUsageCache.RequiresFromKeyedServicesMiddleware(activator); Assert.False(needsMiddleware); } [Fact] public void RequiresFromKeyedServicesMiddlewareAttributeUsed() { var activator = GetReflectionActivator(); var needsMiddleware = FromKeyedServicesUsageCache.RequiresFromKeyedServicesMiddleware(activator); Assert.True(needsMiddleware); } [Fact] public void RequiresFromKeyedServicesMiddlewareCachesForSubsequentCalls() { var activator = GetReflectionActivator(); var first = FromKeyedServicesUsageCache.RequiresFromKeyedServicesMiddleware(activator); var second = FromKeyedServicesUsageCache.RequiresFromKeyedServicesMiddleware(activator); Assert.True(first); Assert.Equal(first, second); } [Fact] public void RequiresFromKeyedServicesMiddlewareNullActivator() { var ex = Assert.Throws(() => FromKeyedServicesUsageCache.RequiresFromKeyedServicesMiddleware(null!)); Assert.Equal("activator", ex.ParamName); } private static ReflectionActivator GetReflectionActivator() where T : class { var services = new ServiceCollection(); services.AddTransient(); var builder = new ContainerBuilder(); builder.Populate(services); using var container = builder.Build(); var typedService = new TypedService(typeof(T)); var registration = container.ComponentRegistry.RegistrationsFor(typedService).Single(); return Assert.IsType(registration.Activator); } private sealed class UsesFromKeyedServices { public UsesFromKeyedServices([FromKeyedServices("k")] object service) { } } private sealed class NoFromKeyedServices { public NoFromKeyedServices(object service) { } } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/KeyTypeManipulationFixture.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Net; namespace Autofac.Extensions.DependencyInjection.Test; public class KeyTypeManipulationFixture { [Fact] public void ChangeToCompatibleTypeAllowsNullMemberInfo() { var actual = KeyTypeManipulation.ChangeToCompatibleType("123", typeof(int), (System.Reflection.MemberInfo)null!); Assert.Equal(123, actual); } [Fact] public void ChangeToCompatibleTypeAllowsNullParameterInfo() { var actual = KeyTypeManipulation.ChangeToCompatibleType("123", typeof(int), (System.Reflection.ParameterInfo)null!); Assert.Equal(123, actual); } [Fact] public void ChangeToCompatibleTypeLooksForTryParseMethod() { var address = "127.0.0.1"; var value = KeyTypeManipulation.ChangeToCompatibleType(address, typeof(IPAddress)); Assert.Equal(value, IPAddress.Parse(address)); } [Fact] public void ChangeToCompatibleTypeNoConversionNeeded() { var actual = KeyTypeManipulation.ChangeToCompatibleType(15, typeof(int)); Assert.Equal(15, actual); } [Fact] public void ChangeToCompatibleTypeNullDestinationType() { var ex = Assert.Throws(() => KeyTypeManipulation.ChangeToCompatibleType("15", null!)); Assert.Equal("destinationType", ex.ParamName); } [Fact] public void ChangeToCompatibleTypeNullReferenceType() { var actual = KeyTypeManipulation.ChangeToCompatibleType(null, typeof(string)); Assert.Null(actual); } [Fact] public void ChangeToCompatibleTypeNullValueType() { var actual = KeyTypeManipulation.ChangeToCompatibleType(null, typeof(int)); Assert.Equal(0, actual); } [Fact] public void ChangeToCompatibleTypeTryParseFails() { var ex = Assert.Throws(() => KeyTypeManipulation.ChangeToCompatibleType("not-valid", typeof(ParseOnlyType))); Assert.Equal(typeof(string), ex.ResolutionKeyType); Assert.Equal(typeof(ParseOnlyType), ex.AttributeKeyType); } [Fact] public void ChangeToCompatibleTypeTypeConverterAttributeCannotConvertFromFallsBackToDefaultConversion() { var actual = KeyTypeManipulation.ChangeToCompatibleType( 15, typeof(string), new TypeConverterAttribute(typeof(NonConvertingConverter))); Assert.Equal("15", actual); } [Fact] public void ChangeToCompatibleTypeTypeConverterAttributeIsInvalid() { var ex = Assert.Throws(() => KeyTypeManipulation.ChangeToCompatibleType("15", typeof(int), new TypeConverterAttribute(typeof(string)))); Assert.Equal(typeof(string), ex.ResolutionKeyType); Assert.Equal(typeof(int), ex.AttributeKeyType); Assert.IsType(ex.InnerException); } [Theory] [MemberData(nameof(ParsingCultures))] public void ChangeToCompatibleTypeUsesInvariantCulture(CultureInfo culture) { TestCulture.With( culture, () => { var actual = KeyTypeManipulation.ChangeToCompatibleType("123.456", typeof(double)); Assert.Equal(123.456, actual); }); } [Fact] public void ChangeToCompatibleTypeUsesTypeConverterOnParameter() { var ctor = typeof(HasTypeConverterAttributes).GetConstructor(new Type[] { typeof(Convertible) }); var member = ctor.GetParameters().First(); var actual = KeyTypeManipulation.ChangeToCompatibleType("25", typeof(Convertible), member) as Convertible; Assert.NotNull(actual); Assert.Equal(25, actual.Value); } [Fact] public void ChangeToCompatibleTypeUsesTypeConverterOnProperty() { var member = typeof(HasTypeConverterAttributes).GetProperty("Property"); var actual = KeyTypeManipulation.ChangeToCompatibleType("25", typeof(Convertible), member) as Convertible; Assert.NotNull(actual); Assert.Equal(25, actual.Value); } public static IEnumerable ParsingCultures() { yield return new object[] { new CultureInfo("en-US") }; yield return new object[] { new CultureInfo("es-MX") }; yield return new object[] { new CultureInfo("it-IT") }; yield return new object[] { CultureInfo.InvariantCulture }; } [SuppressMessage("CA1812", "CA1812", Justification = "Class instantiated through reflection.")] private class Convertible { public int Value { get; set; } } [SuppressMessage("CA1812", "CA1812", Justification = "Class instantiated through reflection.")] private class ConvertibleConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value == null) { return null; } if (value is not string str) { return base.ConvertFrom(context, culture, value); } var converter = TypeDescriptor.GetConverter(typeof(int)); return new Convertible { Value = (int)converter.ConvertFromString(context, culture, str) }; } } [SuppressMessage("CA1812", "CA1812", Justification = "Class instantiated through reflection.")] private class NonConvertingConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return false; } } [SuppressMessage("CA1812", "CA1812", Justification = "Class instantiated through reflection.")] private class HasTypeConverterAttributes { public HasTypeConverterAttributes([TypeConverter(typeof(ConvertibleConverter))] Convertible parameter) { Property = parameter; } [TypeConverter(typeof(ConvertibleConverter))] public Convertible Property { get; set; } } private readonly struct ParseOnlyType { public static bool TryParse(string value, out ParseOnlyType parsed) { parsed = default; return false; } } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/KeyedServiceTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; using MicrosoftServiceKey = Microsoft.Extensions.DependencyInjection.ServiceKeyAttribute; namespace Autofac.Extensions.DependencyInjection.Test; public class KeyedServiceTests { [Fact] public void CollectionKeyedResolutionWithAnyKeyOnNestedParameters() { var services = new ServiceCollection(); // The key should be injected when AnyKey is used. services.AddKeyedTransient("a"); services.AddKeyedTransient("b"); var builder = new ContainerBuilder(); builder.Populate(services); var container = builder.Build(); using var serviceProvider = new AutofacServiceProvider(container); var result = string.Join("", serviceProvider.GetKeyedServices(KeyedService.AnyKey).Select(s => s.Value)); Assert.Equal("ab", result); } [Fact] public void KeyedResolutionWithFromKeyedServicesAndNormalDependency() { var services = new ServiceCollection(); services.AddTransient(); services.AddKeyedTransient("dep"); services.AddKeyedTransient("svc"); var builder = new ContainerBuilder(); builder.Populate(services); var container = builder.Build(); using var serviceProvider = new AutofacServiceProvider(container); var resolved = serviceProvider.GetRequiredKeyedService("svc"); Assert.Equal("dep:normal", resolved.Value); } private interface IService { string Value { get; } } private sealed class ServiceKeyAwareService : IService { private readonly string _resolvedKey; public ServiceKeyAwareService([MicrosoftServiceKey] string resolvedKey) { _resolvedKey = resolvedKey; } public string Value => _resolvedKey; } private interface IKeyedDependency { string Value { get; } } private interface INormalDependency { string Value { get; } } private interface IMixedService { string Value { get; } } private sealed class KeyedDependency : IKeyedDependency { public string Value => "dep"; } private sealed class NormalDependency : INormalDependency { public string Value => "normal"; } private sealed class MixedService : IMixedService { private readonly IKeyedDependency _keyedDependency; private readonly INormalDependency _normalDependency; public MixedService([FromKeyedServices("dep")] IKeyedDependency keyedDependency, INormalDependency normalDependency) { _keyedDependency = keyedDependency; _normalDependency = normalDependency; } public string Value => $"{_keyedDependency.Value}:{_normalDependency.Value}"; } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Properties/AssemblyInfo.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. [assembly: CLSCompliant(false)] ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/ServiceCollectionExtensionsTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test; public sealed class ServiceCollectionExtensionsTests { [Fact] public void AddAutofacReturnsProvidedServiceCollection() { var collection = new ServiceCollection(); var returnedCollection = collection.AddAutofac(); Assert.Same(collection, returnedCollection); } [Fact] public void AddAutofacAddsAutofacServiceProviderFactoryToCollection() { var collection = new ServiceCollection(); collection.AddAutofac(); var service = collection.FirstOrDefault(s => s.ServiceType == typeof(IServiceProviderFactory)); Assert.NotNull(service); Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); } [Fact] public void AddAutofacPassesConfigurationActionToAutofacServiceProviderFactory() { var collection = new ServiceCollection(); collection.AddAutofac(config => config.Register(c => "Foo")); var serviceProvider = collection.BuildServiceProvider(); var factory = (IServiceProviderFactory)serviceProvider.GetService(typeof(IServiceProviderFactory)); var builder = factory.CreateBuilder(collection); Assert.Equal("Foo", builder.Build().Resolve()); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/ServiceProviderExtensionsTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test; public sealed class ServiceProviderExtensionsTests { [Fact] public void GetAutofacRootReturnsLifetimeScope() { var containerBuilder = new ContainerBuilder(); containerBuilder.Populate(new ServiceCollection()); var container = containerBuilder.Build(); var serviceProvider = container.Resolve(); Assert.NotNull(serviceProvider.GetAutofacRoot()); } [Fact] public void GetAutofacRootServiceProviderNotAutofacServiceProviderThrows() => Assert.Throws(() => new ServiceCollection().BuildServiceProvider().GetAutofacRoot()); } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/AssumedBehaviorTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test.Specification; /// /// Additional tests to illustrate undocumented yet assumed behaviors in /// the Microsoft.Extensions.DependencyInjection container/scope. /// public abstract class AssumedBehaviorTests { [Fact] public void DisposingScopeAlsoDisposesServiceProvider() { // You can't resolve things from a scope's service provider // if you dispose the scope. var services = new ServiceCollection().AddScoped(); var rootProvider = CreateServiceProvider(services); var scope = rootProvider.CreateScope(); Assert.NotNull(scope.ServiceProvider.GetRequiredService()); scope.Dispose(); Assert.Throws(() => scope.ServiceProvider.GetRequiredService()); } [Fact] public void DisposingScopeAndProviderOnlyDisposesObjectsOnce() { // Disposing the service provider and then the scope only // runs one disposal on the resolved objects. var services = new ServiceCollection().AddScoped(); var rootProvider = CreateServiceProvider(services); var scope = rootProvider.CreateScope(); var tracker = scope.ServiceProvider.GetRequiredService(); ((IDisposable)scope.ServiceProvider).Dispose(); Assert.True(tracker.Disposed); Assert.Equal(1, tracker.DisposeCount); scope.Dispose(); Assert.Equal(1, tracker.DisposeCount); } [Fact] public void DisposingScopeServiceProviderStopsNewScopes() { // You can't create a new child scope if you've disposed of // the parent scope service provider. var rootProvider = CreateServiceProvider(new ServiceCollection()); using var scope = rootProvider.CreateScope(); ((IDisposable)scope.ServiceProvider).Dispose(); Assert.Throws(() => scope.ServiceProvider.CreateScope()); } [Fact] public void DisposingScopeServiceProviderStopsScopeResolutions() { // You can't resolve things from a scope if you dispose the // scope's service provider. var services = new ServiceCollection().AddScoped(); var rootProvider = CreateServiceProvider(services); using var scope = rootProvider.CreateScope(); Assert.NotNull(scope.ServiceProvider.GetRequiredService()); ((IDisposable)scope.ServiceProvider).Dispose(); Assert.Throws(() => scope.ServiceProvider.GetRequiredService()); } [Fact] public void ResolvedProviderNotSameAsParent() { // Resolving a provider from another provider yields a new object. // (It's not just returning "this" - it's a different IServiceProvider.) var parent = CreateServiceProvider(new ServiceCollection()); var resolved = parent.GetRequiredService(); Assert.NotSame(parent, resolved); } [Fact] public void ResolvedProviderUsesSameScopeAsParent() { // Resolving a provider from another provider will still resolve // items from the same scope. var services = new ServiceCollection().AddScoped(); var root = CreateServiceProvider(services); using var scope = root.CreateScope(); var parent = scope.ServiceProvider; var resolved = parent.GetRequiredService(); Assert.Same(parent.GetRequiredService(), resolved.GetRequiredService()); } [Fact] public void ServiceProviderWillNotResolveAfterDispose() { // You can't resolve things from a service provider // if you dispose it. var services = new ServiceCollection().AddScoped(); var rootProvider = CreateServiceProvider(services); Assert.NotNull(rootProvider.GetRequiredService()); ((IDisposable)rootProvider).Dispose(); Assert.Throws(() => rootProvider.GetRequiredService()); } [Fact] public async Task ServiceProviderDisposesAsync() { // You can't resolve things from a service provider // if you dispose it. var services = new ServiceCollection().AddScoped(); var rootProvider = CreateServiceProvider(services); var tracker = rootProvider.GetRequiredService(); var asyncDisposer = (IAsyncDisposable)rootProvider; await asyncDisposer.DisposeAsync(); Assert.True(tracker.AsyncDisposed); Assert.False(tracker.SyncDisposed); } [Fact] public async Task ServiceScopeDisposesAsync() { // You can't resolve things from a service provider // if you dispose it. var services = new ServiceCollection().AddScoped(); var rootProvider = CreateServiceProvider(services); AsyncDisposeTracker tracker; // Try out the new "CreateAsyncScope" method. var scope = rootProvider.CreateAsyncScope(); await using (scope.ConfigureAwait(false)) { tracker = scope.ServiceProvider.GetRequiredService(); } Assert.True(tracker.AsyncDisposed); Assert.False(tracker.SyncDisposed); } [Fact] public void ServiceScopeFactoryIsSingleton() { // Issue #83: M.E.DI assumes service scope factory is singleton, but // there's no compatibility test for it yet. var services = new ServiceCollection(); var rootProvider = CreateServiceProvider(services); var rootFactory1 = rootProvider.GetRequiredService(); var rootFactory2 = rootProvider.GetRequiredService(); Assert.Same(rootFactory1, rootFactory2); var childScope = rootFactory1.CreateScope(); var childFactory = childScope.ServiceProvider.GetRequiredService(); Assert.Same(rootFactory1, childFactory); } [Fact] public void ServiceScopesAreFlat() { // Issue #83: M.E.DI assumes service scopes are flat - disposing of // a "parent" scope won't actually invalidate a "child" because // they're not related in that fashion. var services = new ServiceCollection().AddSingleton(); var rootProvider = CreateServiceProvider(services); var outerScope = rootProvider.CreateScope(); var innerScope = outerScope.ServiceProvider.CreateScope(); outerScope.Dispose(); // This part will blow up if the scopes are hierarchical. innerScope.ServiceProvider.GetRequiredService(); innerScope.Dispose(); } [Fact] public void ServiceInstancesRegisteredAreNotDisposedWhenTheProviderIsDisposed() { using var externalService = new DisposeTracker(); var services = new ServiceCollection().AddSingleton(externalService); var rootProvider = CreateServiceProvider(services); ((IDisposable)rootProvider).Dispose(); Assert.False(externalService.Disposed); } protected abstract IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection); [SuppressMessage("CA1812", "CA1812", Justification = "Class instantiated through reflection.")] private class DisposeTrackerConsumer { public DisposeTrackerConsumer(IEnumerable trackers) { Trackers = trackers; } public IEnumerable Trackers { get; } } [SuppressMessage("CA1812", "CA1812", Justification = "Instantiated via dependency injection.")] private class DisposeTracker : IDisposable { public int DisposeCount { get; set; } public bool Disposed { get; set; } public void Dispose() { Disposed = true; DisposeCount++; } } [SuppressMessage("CA1812", "CA1812", Justification = "Instantiated via dependency injection.")] private class AsyncDisposeTracker : IDisposable, IAsyncDisposable { public bool SyncDisposed { get; set; } public bool AsyncDisposed { get; set; } public void Dispose() { SyncDisposed = true; } public async ValueTask DisposeAsync() { await Task.Delay(1).ConfigureAwait(false); AsyncDisposed = true; } } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/BuilderAssumedBehaviorTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class BuilderAssumedBehaviorTests : AssumedBehaviorTests { protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { var builder = new ContainerBuilder(); builder.Populate(serviceCollection); var container = builder.Build(); return container.Resolve(); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/BuilderKeyedSpecificationTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Specification; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class BuilderKeyedSpecificationTests : KeyedDependencyInjectionSpecificationTests { public override bool SupportsIServiceProviderIsKeyedService => true; protected override IServiceProvider CreateServiceProvider(IServiceCollection collection) { var builder = new ContainerBuilder(); builder.Populate(collection); var container = builder.Build(); return container.Resolve(); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/BuilderSpecificationTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Specification; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class BuilderSpecificationTests : DependencyInjectionSpecificationTests { public override bool SupportsIServiceProviderIsService => true; protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { var builder = new ContainerBuilder(); builder.Populate(serviceCollection); var container = builder.Build(); return container.Resolve(); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/ChildScopeFactoryAssumedBehaviorTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class ChildScopeFactoryAssumedBehaviorTests : AssumedBehaviorTests { protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { var container = new ContainerBuilder().Build(); var rootScope = container.BeginLifetimeScope(); var factory = new AutofacChildLifetimeScopeServiceProviderFactory(() => rootScope); return factory.CreateServiceProvider(factory.CreateBuilder(serviceCollection)); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/ChildScopeFactoryKeyedSpecificationTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Specification; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class ChildScopeFactoryKeyedSpecificationTests : KeyedDependencyInjectionSpecificationTests { public override bool SupportsIServiceProviderIsKeyedService => true; protected override IServiceProvider CreateServiceProvider(IServiceCollection collection) { var container = new ContainerBuilder().Build(); var rootScope = container.BeginLifetimeScope(); var factory = new AutofacChildLifetimeScopeServiceProviderFactory(() => rootScope); return factory.CreateServiceProvider(factory.CreateBuilder(collection)); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/ChildScopeFactorySpecificationTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Specification; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class ChildScopeFactorySpecificationTests : DependencyInjectionSpecificationTests { public override bool SupportsIServiceProviderIsService => true; protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { var container = new ContainerBuilder().Build(); var rootScope = container.BeginLifetimeScope(); var factory = new AutofacChildLifetimeScopeServiceProviderFactory(() => rootScope); return factory.CreateServiceProvider(factory.CreateBuilder(serviceCollection)); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/FactoryAssumedBehaviorTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class FactoryAssumedBehaviorTests : AssumedBehaviorTests { protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { var factory = new AutofacServiceProviderFactory(); return factory.CreateServiceProvider(factory.CreateBuilder(serviceCollection)); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/FactoryKeyedSpecificationTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Specification; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class FactoryKeyedSpecificationTests : KeyedDependencyInjectionSpecificationTests { public override bool SupportsIServiceProviderIsKeyedService => true; protected override IServiceProvider CreateServiceProvider(IServiceCollection collection) { var factory = new AutofacServiceProviderFactory(); return factory.CreateServiceProvider(factory.CreateBuilder(collection)); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/FactorySpecificationTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Specification; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class FactorySpecificationTests : DependencyInjectionSpecificationTests { public override bool SupportsIServiceProviderIsService => true; protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { var factory = new AutofacServiceProviderFactory(); return factory.CreateServiceProvider(factory.CreateBuilder(serviceCollection)); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/Specification/MicrosoftAssumedBehaviorTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.Extensions.DependencyInjection; namespace Autofac.Extensions.DependencyInjection.Test.Specification; public class MicrosoftAssumedBehaviorTests : AssumedBehaviorTests { protected override IServiceProvider CreateServiceProvider(IServiceCollection serviceCollection) { return serviceCollection.BuildServiceProvider(); } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/TestCulture.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Globalization; namespace Autofac.Extensions.DependencyInjection.Test; public static class TestCulture { public static void With(CultureInfo culture, Action test) { var originalCulture = Thread.CurrentThread.CurrentCulture; var originalUICulture = Thread.CurrentThread.CurrentUICulture; Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; CultureInfo.CurrentCulture.ClearCachedData(); CultureInfo.CurrentUICulture.ClearCachedData(); try { test?.Invoke(); } finally { Thread.CurrentThread.CurrentCulture = originalCulture; Thread.CurrentThread.CurrentUICulture = originalUICulture; CultureInfo.CurrentCulture.ClearCachedData(); CultureInfo.CurrentUICulture.ClearCachedData(); } } } ================================================ FILE: test/Autofac.Extensions.DependencyInjection.Test/TypeExtensionsTests.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Autofac.Extensions.DependencyInjection.Test; public class TypeExtensionsTests { [Fact] public void IsCollectionCachesLookups() { var type = typeof(IReadOnlyList); var first = type.IsCollection(); var second = type.IsCollection(); Assert.True(first); Assert.Equal(first, second); } [Theory] [InlineData(typeof(int[]))] [InlineData(typeof(IEnumerable))] [InlineData(typeof(IList))] [InlineData(typeof(ICollection))] [InlineData(typeof(IReadOnlyCollection))] [InlineData(typeof(IReadOnlyList))] public void IsCollectionSupportedCollectionTypes(Type type) { Assert.True(type.IsCollection()); } [Theory] [InlineData(typeof(string))] [InlineData(typeof(List))] [InlineData(typeof(Dictionary))] [InlineData(typeof(IEnumerable<>))] public void IsCollectionUnsupportedTypes(Type type) { Assert.False(type.IsCollection()); } } ================================================ FILE: test/Integration.Net10/Controllers/DateController.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.AspNetCore.Mvc; namespace Integration.Net10.Controllers; [ApiController] [Route("[controller]")] public class DateController : ControllerBase { public DateController(IDateProvider dateProvider) { DateProvider = dateProvider; } public IDateProvider DateProvider { get; } [HttpGet] public ActionResult Get() => DateProvider.GetDate(); } ================================================ FILE: test/Integration.Net10/DateProvider.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Integration.Net10; public class DateProvider : IDateProvider { public DateTimeOffset GetDate() => DateTimeOffset.UtcNow; } ================================================ FILE: test/Integration.Net10/IDateProvider.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Integration.Net10; public interface IDateProvider { DateTimeOffset GetDate(); } ================================================ FILE: test/Integration.Net10/Integration.Net10.csproj ================================================ net10.0 $(NoWarn);CS1591 true ../../Autofac.snk true enable ../../build/Test.ruleset AllEnabledByDefault true enable all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: test/Integration.Net10/Program.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Autofac.Extensions.DependencyInjection; namespace Integration.Net10; public static class Program { public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); public static async Task Main(string[] args) => await CreateHostBuilder(args).Build().RunAsync().ConfigureAwait(false); } ================================================ FILE: test/Integration.Net10/Properties/AssemblyInfo.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. [assembly: CLSCompliant(false)] ================================================ FILE: test/Integration.Net10/Properties/launchSettings.json ================================================ { "profiles": { "Integration.Net10": { "applicationUrl": "https://localhost:7154;http://localhost:7155", "commandName": "Project", "dotnetRunMessages": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "launchBrowser": true } } } ================================================ FILE: test/Integration.Net10/Startup.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Diagnostics.CodeAnalysis; using Autofac; namespace Integration.Net10; [SuppressMessage("CA1052", "CA1052", Justification = "Startup must not be a static class.")] public class Startup { public static void Configure(IApplicationBuilder app) { app.UseRouting() .UseEndpoints(endpoints => endpoints.MapControllers()); } public static void ConfigureServices(IServiceCollection services) { services.AddMvc(); } public static void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType().As(); } } ================================================ FILE: test/Integration.Net10/appsettings.Development.json ================================================ { "Logging": { "LogLevel": { "Default": "Information" } } } ================================================ FILE: test/Integration.Net10/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "None" } } } ================================================ FILE: test/Integration.Net8/Controllers/DateController.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Microsoft.AspNetCore.Mvc; namespace Integration.Net8.Controllers; [ApiController] [Route("[controller]")] public class DateController : ControllerBase { public DateController(IDateProvider dateProvider) { DateProvider = dateProvider; } public IDateProvider DateProvider { get; } [HttpGet] public ActionResult Get() => DateProvider.GetDate(); } ================================================ FILE: test/Integration.Net8/DateProvider.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Integration.Net8; public class DateProvider : IDateProvider { public DateTimeOffset GetDate() => DateTimeOffset.UtcNow; } ================================================ FILE: test/Integration.Net8/IDateProvider.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. namespace Integration.Net8; public interface IDateProvider { DateTimeOffset GetDate(); } ================================================ FILE: test/Integration.Net8/Integration.Net8.csproj ================================================ net8.0 $(NoWarn);CS1591 true ../../Autofac.snk true enable ../../build/Test.ruleset AllEnabledByDefault true enable all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: test/Integration.Net8/Program.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using Autofac.Extensions.DependencyInjection; namespace Integration.Net8; public static class Program { public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); public static async Task Main(string[] args) => await CreateHostBuilder(args).Build().RunAsync().ConfigureAwait(false); } ================================================ FILE: test/Integration.Net8/Properties/AssemblyInfo.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. [assembly: CLSCompliant(false)] ================================================ FILE: test/Integration.Net8/Properties/launchSettings.json ================================================ { "profiles": { "Integration.Net8": { "applicationUrl": "https://localhost:7154;http://localhost:7155", "commandName": "Project", "dotnetRunMessages": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "launchBrowser": true } } } ================================================ FILE: test/Integration.Net8/Startup.cs ================================================ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System.Diagnostics.CodeAnalysis; using Autofac; namespace Integration.Net8; [SuppressMessage("CA1052", "CA1052", Justification = "Startup must not be a static class.")] public class Startup { public static void Configure(IApplicationBuilder app) { app.UseRouting() .UseEndpoints(endpoints => endpoints.MapControllers()); } public static void ConfigureServices(IServiceCollection services) { services.AddMvc(); } public static void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType().As(); } } ================================================ FILE: test/Integration.Net8/appsettings.Development.json ================================================ { "Logging": { "LogLevel": { "Default": "Information" } } } ================================================ FILE: test/Integration.Net8/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "None" } } }