├── .editorconfig
├── .git-blame-ignore-revs
├── .gitattributes
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── Autofac.Configuration.sln
├── Autofac.snk
├── Directory.Build.props
├── Directory.Build.targets
├── LICENSE
├── NuGet.Config
├── README.md
├── appveyor.yml
├── build.ps1
├── build
├── Analyzers.ruleset
├── Autofac.Build.psd1
├── Autofac.Build.psm1
├── Test.ruleset
├── icon.png
└── stylecop.json
├── codecov.yml
├── global.json
├── src
└── Autofac.Configuration
│ ├── Autofac.Configuration.csproj
│ ├── ConfigurationModule.cs
│ ├── ConfigurationResources.resx
│ ├── Core
│ ├── ComponentRegistrar.cs
│ ├── ConfigurationExtensions.cs
│ ├── ConfigurationRegistrar.cs
│ └── ModuleRegistrar.cs
│ ├── IComponentRegistrar.cs
│ ├── IConfigurationRegistrar.cs
│ ├── IModuleRegistrar.cs
│ ├── NullableAttributes.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ └── Util
│ ├── ConfiguredDictionaryParameter.cs
│ ├── ConfiguredListParameter.cs
│ ├── ReflectionExtensions.cs
│ ├── StringExtensions.cs
│ └── TypeManipulation.cs
└── test
└── Autofac.Configuration.Test
├── AssertionHelpers.cs
├── Autofac.Configuration.Test.csproj
├── Core
├── ComponentRegistrarFixture.cs
├── ConfigurationExtensionsFixture.cs
├── ConfigurationExtensions_DictionaryParametersFixture.cs
├── ConfigurationExtensions_EnumerableParametersFixture.cs
├── ConfigurationRegistrarFixture.cs
├── ModuleConfiguration_ComplexTypeFixture.cs
└── ModuleRegistrarFixture.cs
├── EmbeddedConfiguration.cs
├── EmbeddedConfigurationProvider.cs
├── Files
├── ComponentRegistrar_ComponentWithMetadata.json
├── ComponentRegistrar_ComponentsMissingName.xml
├── ComponentRegistrar_EnableAutoActivation.json
├── ComponentRegistrar_EnablePropertyInjection.json
├── ComponentRegistrar_ExternalOwnership.json
├── ComponentRegistrar_InstancePerDependency.json
├── ComponentRegistrar_MetadataMissingName.xml
├── ComponentRegistrar_SameTypeRegisteredMultipleTimes.json
├── ComponentRegistrar_ServicesMissingName.xml
├── ComponentRegistrar_SingletonWithTwoServices.xml
├── ConfigurationExtensions_DictionaryParameters.xml
├── ConfigurationExtensions_EnumerableParameters.xml
├── ConfigurationExtensions_Parameters.json
├── ModuleConfiguration_ComplexType.json
├── ModuleRegistrar_ModuleWithNoPublicConstructor.json
├── ModuleRegistrar_ModulesMissingName.xml
├── ModuleRegistrar_SameModuleRegisteredMultipleTimes.json
└── ModuleRegistrar_SameModuleWithVaryingConstructorParams.json
├── Properties
└── AssemblyInfo.cs
├── TestCulture.cs
└── Util
├── ReflectionExtensionsFixture.cs
└── TypeManipulationFixture.cs
/.editorconfig:
--------------------------------------------------------------------------------
1 | ; EditorConfig to support per-solution formatting.
2 | ; Use the EditorConfig VS add-in to make this work.
3 | ; http://editorconfig.org/
4 |
5 | ; This is the default for the codeline.
6 | root = true
7 |
8 | [*]
9 | indent_style = space
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 |
13 | ; .NET Code - almost, but not exactly, the same suggestions as corefx
14 | ; https://github.com/dotnet/corefx/blob/master/.editorconfig
15 | [*.cs]
16 | indent_size = 4
17 | charset = utf-8-bom
18 |
19 | ; New line preferences
20 | csharp_new_line_before_open_brace = all
21 | csharp_new_line_before_else = true
22 | csharp_new_line_before_catch = true
23 | csharp_new_line_before_finally = true
24 | csharp_new_line_before_members_in_object_initializers = true
25 | csharp_new_line_before_members_in_anonymous_types = true
26 | csharp_new_line_between_query_expression_clauses = true
27 |
28 | ; Indentation preferences
29 | csharp_indent_block_contents = true
30 | csharp_indent_braces = false
31 | csharp_indent_case_contents = true
32 | csharp_indent_case_contents_when_block = true
33 | csharp_indent_switch_labels = true
34 | csharp_indent_labels = one_less_than_current
35 |
36 | ; Modifier preferences
37 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
38 |
39 | ; Avoid this. unless absolutely necessary
40 | dotnet_style_qualification_for_field = false:suggestion
41 | dotnet_style_qualification_for_property = false:suggestion
42 | dotnet_style_qualification_for_method = false:suggestion
43 | dotnet_style_qualification_for_event = false:suggestion
44 |
45 | ; Types: use keywords instead of BCL types, using var is fine.
46 | csharp_style_var_when_type_is_apparent = false:none
47 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
48 | dotnet_style_predefined_type_for_member_access = true:suggestion
49 |
50 | ; Name all constant fields using PascalCase
51 | dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = warning
52 | dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
53 | dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
54 | dotnet_naming_symbols.constant_fields.applicable_kinds = field
55 | dotnet_naming_symbols.constant_fields.required_modifiers = const
56 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case
57 |
58 | ; Static fields should be _camelCase
59 | dotnet_naming_rule.static_fields_should_be_camel_case.severity = warning
60 | dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
61 | dotnet_naming_rule.static_fields_should_be_camel_case.style = camel_case_underscore_style
62 | dotnet_naming_symbols.static_fields.applicable_kinds = field
63 | dotnet_naming_symbols.static_fields.required_modifiers = static
64 | dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
65 |
66 | ; Static readonly fields should be PascalCase
67 | dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.severity = warning
68 | dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.symbols = static_readonly_fields
69 | dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.style = pascal_case_style
70 | dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field
71 | dotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly
72 | dotnet_naming_symbols.static_readonly_fields.applicable_accessibilities = private, internal, private_protected
73 |
74 | ; Internal and private fields should be _camelCase
75 | dotnet_naming_rule.camel_case_for_private_internal_fields.severity = warning
76 | dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
77 | dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
78 | dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
79 | dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
80 | dotnet_naming_style.camel_case_underscore_style.required_prefix = _
81 | dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
82 |
83 | ; Code style defaults
84 | csharp_using_directive_placement = outside_namespace:suggestion
85 | dotnet_sort_system_directives_first = true
86 | csharp_prefer_braces = true:refactoring
87 | csharp_preserve_single_line_blocks = true:none
88 | csharp_preserve_single_line_statements = false:none
89 | csharp_prefer_static_local_function = true:suggestion
90 | csharp_prefer_simple_using_statement = false:none
91 | csharp_style_prefer_switch_expression = true:suggestion
92 |
93 | ; Code quality
94 | dotnet_style_readonly_field = true:suggestion
95 | dotnet_code_quality_unused_parameters = non_public:suggestion
96 |
97 | ; Expression-level preferences
98 | dotnet_style_object_initializer = true:suggestion
99 | dotnet_style_collection_initializer = true:suggestion
100 | dotnet_style_explicit_tuple_names = true:suggestion
101 | dotnet_style_coalesce_expression = true:suggestion
102 | dotnet_style_null_propagation = true:suggestion
103 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
104 | dotnet_style_prefer_inferred_tuple_names = true:suggestion
105 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
106 | dotnet_style_prefer_auto_properties = true:suggestion
107 | dotnet_style_prefer_conditional_expression_over_assignment = true:refactoring
108 | dotnet_style_prefer_conditional_expression_over_return = true:refactoring
109 | csharp_prefer_simple_default_expression = true:suggestion
110 |
111 | # Expression-bodied members
112 | csharp_style_expression_bodied_methods = true:refactoring
113 | csharp_style_expression_bodied_constructors = true:refactoring
114 | csharp_style_expression_bodied_operators = true:refactoring
115 | csharp_style_expression_bodied_properties = true:refactoring
116 | csharp_style_expression_bodied_indexers = true:refactoring
117 | csharp_style_expression_bodied_accessors = true:refactoring
118 | csharp_style_expression_bodied_lambdas = true:refactoring
119 | csharp_style_expression_bodied_local_functions = true:refactoring
120 |
121 | # Pattern matching
122 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
123 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
124 | csharp_style_inlined_variable_declaration = true:suggestion
125 |
126 | # Null checking preferences
127 | csharp_style_throw_expression = true:suggestion
128 | csharp_style_conditional_delegate_call = true:suggestion
129 |
130 | # Other features
131 | csharp_style_namespace_declarations = file_scoped:suggestion
132 | csharp_style_prefer_index_operator = false:none
133 | csharp_style_prefer_range_operator = false:none
134 | csharp_style_pattern_local_over_anonymous_function = false:none
135 |
136 | # Space preferences
137 | csharp_space_after_cast = false
138 | csharp_space_after_colon_in_inheritance_clause = true
139 | csharp_space_after_comma = true
140 | csharp_space_after_dot = false
141 | csharp_space_after_keywords_in_control_flow_statements = true
142 | csharp_space_after_semicolon_in_for_statement = true
143 | csharp_space_around_binary_operators = before_and_after
144 | csharp_space_around_declaration_statements = do_not_ignore
145 | csharp_space_before_colon_in_inheritance_clause = true
146 | csharp_space_before_comma = false
147 | csharp_space_before_dot = false
148 | csharp_space_before_open_square_brackets = false
149 | csharp_space_before_semicolon_in_for_statement = false
150 | csharp_space_between_empty_square_brackets = false
151 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
152 | csharp_space_between_method_call_name_and_opening_parenthesis = false
153 | csharp_space_between_method_call_parameter_list_parentheses = false
154 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
155 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
156 | csharp_space_between_method_declaration_parameter_list_parentheses = false
157 | csharp_space_between_parentheses = false
158 | csharp_space_between_square_brackets = false
159 |
160 | ; .NET project files and MSBuild - match defaults for VS
161 | [*.{csproj,nuspec,proj,projitems,props,shproj,targets,vbproj,vcxproj,vcxproj.filters,vsixmanifest,vsct}]
162 | indent_size = 2
163 |
164 | ; .NET solution files - match defaults for VS
165 | [*.sln]
166 | indent_style = tab
167 |
168 | ; Config - match XML and default nuget.config template
169 | [*.config]
170 | indent_size = 2
171 |
172 | ; Resources - match defaults for VS
173 | [*.resx]
174 | indent_size = 2
175 |
176 | ; Static analysis rulesets - match defaults for VS
177 | [*.ruleset]
178 | indent_size = 2
179 |
180 | ; HTML, XML - match defaults for VS
181 | [*.{cshtml,html,xml}]
182 | indent_size = 4
183 |
184 | ; JavaScript and JS mixes - match eslint settings; JSON also matches .NET Core templates
185 | [*.{js,json,ts,vue}]
186 | indent_size = 2
187 |
188 | ; Markdown - match markdownlint settings
189 | [*.{md,markdown}]
190 | indent_size = 2
191 |
192 | ; PowerShell - match defaults for New-ModuleManifest and PSScriptAnalyzer Invoke-Formatter
193 | [*.{ps1,psd1,psm1}]
194 | indent_size = 4
195 | charset = utf-8-bom
196 |
197 | ; ReStructuredText - standard indentation format from examples
198 | [*.rst]
199 | indent_size = 2
200 |
--------------------------------------------------------------------------------
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # Ignore revisions in git blame - set your git config to use the file by convention:
2 | # git config --global blame.ignoreRevsFile .git-blame-ignore-revs
3 | #
4 | # Optional additional git config:
5 | # Mark any lines that have had a commit skipped using --ignore-rev with a `?`
6 | # git config --global blame.markIgnoredLines true
7 | # Mark any lines that were added in a skipped commit and can not be attributed with a `*`
8 | # git config --global blame.markUnblamableLines true
9 |
10 | # Convert to file-scoped namespaces.
11 | e646ad26bf2f484f8b9063d2d4d08a034027ff8e
12 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.doc diff=astextplain
2 | *.DOC diff=astextplain
3 | *.docx diff=astextplain
4 | *.DOCX diff=astextplain
5 | *.dot diff=astextplain
6 | *.DOT diff=astextplain
7 | *.pdf diff=astextplain
8 | *.PDF diff=astextplain
9 | *.rtf diff=astextplain
10 | *.RTF diff=astextplain
11 |
12 | *.jpg binary
13 | *.png binary
14 | *.gif binary
15 |
16 | *.cs text=auto diff=csharp
17 | *.vb text=auto
18 | *.resx text=auto
19 | *.c text=auto
20 | *.cpp text=auto
21 | *.cxx text=auto
22 | *.h text=auto
23 | *.hxx text=auto
24 | *.py text=auto
25 | *.rb text=auto
26 | *.java text=auto
27 | *.html text=auto
28 | *.htm text=auto
29 | *.css text=auto
30 | *.scss text=auto
31 | *.sass text=auto
32 | *.less text=auto
33 | *.js text=auto
34 | *.lisp text=auto
35 | *.clj text=auto
36 | *.sql text=auto
37 | *.php text=auto
38 | *.lua text=auto
39 | *.m text=auto
40 | *.asm text=auto
41 | *.erl text=auto
42 | *.fs text=auto
43 | *.fsx text=auto
44 | *.hs text=auto
45 |
46 | *.csproj text=auto
47 | *.vbproj text=auto
48 | *.fsproj text=auto
49 | *.dbproj text=auto
50 | *.sln text=auto eol=crlf
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Project specific files
5 | artifacts/
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.sln.docstates
11 | *.ide
12 | Index.dat
13 | Storage.dat
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Rr]elease/
18 | x64/
19 | [Bb]in/
20 | [Oo]bj/
21 |
22 | # Visual Studio 2015 cache/options directory
23 | .dotnet/
24 | .vs/
25 | .cr/
26 |
27 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
28 | !packages/*/build/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 | *.TestResults.xml
34 | results/
35 |
36 | *_i.c
37 | *_p.c
38 | *.ilk
39 | *.meta
40 | *.obj
41 | *.pch
42 | *.pdb
43 | *.pgc
44 | *.pgd
45 | *.rsp
46 | *.sbr
47 | *.tlb
48 | *.tli
49 | *.tlh
50 | *.tmp
51 | *.tmp_proj
52 | *.log
53 | *.vspscc
54 | *.vssscc
55 | .builds
56 | *.pidb
57 | *.log
58 | *.scc
59 |
60 | # Visual C++ cache files
61 | ipch/
62 | *.aps
63 | *.ncb
64 | *.opensdf
65 | *.sdf
66 | *.cachefile
67 |
68 | # Visual Studio profiler
69 | *.psess
70 | *.vsp
71 | *.vspx
72 |
73 | # Guidance Automation Toolkit
74 | *.gpState
75 |
76 | # ReSharper is a .NET coding add-in
77 | _ReSharper*/
78 | *.[Rr]e[Ss]harper
79 |
80 | # TeamCity is a build add-in
81 | _TeamCity*
82 |
83 | # DotCover is a Code Coverage Tool
84 | *.dotCover
85 |
86 | # Coverage
87 | coverage.*
88 | codecov.sh
89 | coverage/
90 |
91 | # NCrunch
92 | *.ncrunch*
93 | .*crunch*.local.xml
94 |
95 | # Installshield output folder
96 | [Ee]xpress/
97 |
98 | # DocProject is a documentation generator add-in
99 | DocProject/buildhelp/
100 | DocProject/Help/*.HxT
101 | DocProject/Help/*.HxC
102 | DocProject/Help/*.hhc
103 | DocProject/Help/*.hhk
104 | DocProject/Help/*.hhp
105 | DocProject/Help/Html2
106 | DocProject/Help/html
107 |
108 | # Click-Once directory
109 | publish/
110 |
111 | # Publish Web Output
112 | *.[Pp]ublish.xml
113 | *.pubxml
114 |
115 | # NuGet Packages Directory
116 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
117 | packages/
118 |
119 | # Windows Azure Build Output
120 | csx
121 | *.build.csdef
122 |
123 | # Windows Store app package directory
124 | AppPackages/
125 |
126 | # Others
127 | sql/
128 | *.Cache
129 | ClientBin/
130 | [Ss]tyle[Cc]op.*
131 | !stylecop.json
132 | ~$*
133 | *~
134 | *.dbmdl
135 | *.pfx
136 | *.publishsettings
137 | node_modules/
138 | bower_components/
139 | wwwroot/
140 | project.lock.json
141 |
142 | # RIA/Silverlight projects
143 | Generated_Code/
144 |
145 | # Backup & report files from converting an old project file to a newer
146 | # Visual Studio version. Backup files are not needed, because we have git ;-)
147 | _UpgradeReport_Files/
148 | Backup*/
149 | UpgradeLog*.XML
150 | UpgradeLog*.htm
151 |
152 | # SQL Server files
153 | App_Data/*.mdf
154 | App_Data/*.ldf
155 |
156 | # =========================
157 | # Windows detritus
158 | # =========================
159 |
160 | # Windows image file caches
161 | Thumbs.db
162 | ehthumbs.db
163 |
164 | # Folder config file
165 | Desktop.ini
166 |
167 | # Recycle Bin used on file shares
168 | $RECYCLE.BIN/
169 |
170 | # Mac crap
171 | .DS_Store
172 |
173 | # JetBrains Rider
174 | .idea
175 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-dotnettools.csdevkit",
4 | "editorconfig.editorconfig",
5 | "davidanson.vscode-markdownlint"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "configurations": [
3 | {
4 | "args": [
5 | ],
6 | "console": "internalConsole",
7 | "cwd": "${workspaceFolder}/test/Autofac.Configuration.Test",
8 | "name": ".NET Core Launch (console)",
9 | "preLaunchTask": "build",
10 | "program": "${workspaceFolder}/test/Autofac.Configuration.Test/bin/Debug/net8.0/Autofac.Configuration.Test.dll",
11 | "request": "launch",
12 | "stopAtEntry": false,
13 | "type": "coreclr"
14 | },
15 | {
16 | "name": ".NET Core Attach",
17 | "processId": "${command:pickProcess}",
18 | "request": "attach",
19 | "type": "coreclr"
20 | }
21 | ],
22 | "version": "0.2.0"
23 | }
24 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "autofac",
4 | "autowired",
5 | "cref",
6 | "cyclomatic",
7 | "langword",
8 | "listheader",
9 | "paramref",
10 | "seealso",
11 | "typeparam",
12 | "xunit"
13 | ],
14 | "coverage-gutters.coverageBaseDir": "artifacts/coverage/**",
15 | "coverage-gutters.coverageFileNames": [
16 | "coverage.info"
17 | ],
18 | "dotnet-test-explorer.runInParallel": true,
19 | "dotnet-test-explorer.testProjectPath": "test/**/*Test.csproj",
20 | "dotnet.unitTestDebuggingOptions": {
21 | "enableStepFiltering": false,
22 | "justMyCode": false,
23 | "requireExactSource": false,
24 | "sourceLinkOptions": {
25 | "*": {
26 | "enabled": true
27 | }
28 | },
29 | "suppressJITOptimizations": true,
30 | "symbolOptions": {
31 | "searchNuGetOrgSymbolServer": true
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "tasks": [
3 | {
4 | "args": [
5 | "build",
6 | "${workspaceFolder}/Autofac.Configuration.sln",
7 | "/property:GenerateFullPaths=true",
8 | "/consoleloggerparameters:NoSummary"
9 | ],
10 | "command": "dotnet",
11 | "group": {
12 | "isDefault": true,
13 | "kind": "build"
14 | },
15 | "label": "build",
16 | "problemMatcher": "$msCompile",
17 | "type": "process"
18 | },
19 | {
20 | "args": [
21 | "test",
22 | "${workspaceFolder}/Autofac.Configuration.sln",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary",
25 | "--results-directory",
26 | "\"artifacts/coverage\"",
27 | "--logger:trx",
28 | "/p:CoverletOutput=\"${workspaceFolder}/artifacts/coverage/\"",
29 | "/p:CollectCoverage=true",
30 | "/p:CoverletOutputFormat=lcov",
31 | "/p:Exclude=\"[System.*]*\"",
32 | "-m:1"
33 | ],
34 | "command": "dotnet",
35 | "group": {
36 | "isDefault": true,
37 | "kind": "test"
38 | },
39 | "label": "test",
40 | "problemMatcher": "$msCompile",
41 | "type": "process"
42 | }
43 | ],
44 | "version": "2.0.0"
45 | }
46 |
--------------------------------------------------------------------------------
/Autofac.Configuration.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30114.105
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{32285FA4-6B46-4D6B-A840-2B13E4C8B58E}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Autofac.Configuration", "src\Autofac.Configuration\Autofac.Configuration.csproj", "{614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Autofac.Configuration.Test", "test\Autofac.Configuration.Test\Autofac.Configuration.Test.csproj", "{4AF3EB56-F763-4CF7-BEAC-8A86487F0883}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5ED4AA21-A1C8-4A0A-AF40-6C45EC71F617}"
15 | ProjectSection(SolutionItems) = preProject
16 | appveyor.yml = appveyor.yml
17 | global.json = global.json
18 | NuGet.Config = NuGet.Config
19 | EndProjectSection
20 | EndProject
21 | Global
22 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
23 | Debug|Any CPU = Debug|Any CPU
24 | Debug|Mixed Platforms = Debug|Mixed Platforms
25 | Debug|x86 = Debug|x86
26 | Release|Any CPU = Release|Any CPU
27 | Release|Mixed Platforms = Release|Mixed Platforms
28 | Release|x86 = Release|x86
29 | EndGlobalSection
30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
31 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
34 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
35 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Debug|x86.ActiveCfg = Debug|Any CPU
36 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Debug|x86.Build.0 = Debug|Any CPU
37 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
38 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Release|Any CPU.Build.0 = Release|Any CPU
39 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
40 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
41 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Release|x86.ActiveCfg = Release|Any CPU
42 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F}.Release|x86.Build.0 = Release|Any CPU
43 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
46 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
47 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Debug|x86.ActiveCfg = Debug|Any CPU
48 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Debug|x86.Build.0 = Debug|Any CPU
49 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Release|Any CPU.Build.0 = Release|Any CPU
51 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
52 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Release|Mixed Platforms.Build.0 = Release|Any CPU
53 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Release|x86.ActiveCfg = Release|Any CPU
54 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883}.Release|x86.Build.0 = Release|Any CPU
55 | EndGlobalSection
56 | GlobalSection(SolutionProperties) = preSolution
57 | HideSolutionNode = FALSE
58 | EndGlobalSection
59 | GlobalSection(NestedProjects) = preSolution
60 | {614EF0F2-C00B-4A34-8D13-A778EDE4CA2F} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
61 | {4AF3EB56-F763-4CF7-BEAC-8A86487F0883} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
62 | EndGlobalSection
63 | GlobalSection(ExtensibilityGlobals) = postSolution
64 | SolutionGuid = {2642836D-6510-4756-8615-9B34C9FB9211}
65 | EndGlobalSection
66 | EndGlobal
67 |
--------------------------------------------------------------------------------
/Autofac.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autofac/Autofac.Configuration/4fff3f5b19ec62bc6cb995bd5c15f4fac8c2c0f9/Autofac.snk
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright © 2014 Autofac Project
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Autofac.Configuration
2 |
3 | Configuration support for [Autofac](https://autofac.org).
4 |
5 | [](https://ci.appveyor.com/project/Autofac/autofac-configuration)
6 |
7 | Please file issues and pull requests for this package [in this repository](https://github.com/autofac/Autofac.Configuration/issues) rather than in the Autofac core repo.
8 |
9 | - [Documentation](https://autofac.readthedocs.io/en/latest/configuration/xml.html)
10 | - [NuGet](https://www.nuget.org/packages/Autofac.Configuration)
11 | - [Contributing](https://autofac.readthedocs.io/en/latest/contributors.html)
12 | - [Open in Visual Studio Code](https://open.vscode.dev/autofac/Autofac.Configuration)
13 |
14 | ## Quick Start
15 |
16 | The basic steps to getting configuration set up with your application are:
17 |
18 | 1. Set up your configuration in JSON or XML files that can be read by `Microsoft.Extensions.Configuration`.
19 | - JSON configuration uses `Microsoft.Extensions.Configuration.Json`
20 | - XML configuration uses `Microsoft.Extensions.Configuration.Xml`
21 | 2. Build the configuration using the `Microsoft.Extensions.Configuration.ConfigurationBuilder`.
22 | 3. Create a new `Autofac.Configuration.ConfigurationModule` and pass the built `Microsoft.Extensions.Configuration.IConfiguration` into it.
23 | 4. Register the `Autofac.Configuration.ConfigurationModule` with your container.
24 |
25 | A configuration file with some simple registrations looks like this:
26 |
27 | ```json
28 | {
29 | "defaultAssembly": "Autofac.Example.Calculator",
30 | "components": [{
31 | "type": "Autofac.Example.Calculator.Addition.Add, Autofac.Example.Calculator.Addition",
32 | "services": [{
33 | "type": "Autofac.Example.Calculator.Api.IOperation"
34 | }],
35 | "injectProperties": true
36 | }, {
37 | "type": "Autofac.Example.Calculator.Division.Divide, Autofac.Example.Calculator.Division",
38 | "services": [{
39 | "type": "Autofac.Example.Calculator.Api.IOperation"
40 | }],
41 | "parameters": {
42 | "places": 4
43 | }
44 | }]
45 | }
46 | ```
47 |
48 | JSON is cleaner and easier to read, but if you prefer XML, the same configuration looks like this:
49 |
50 | ```xml
51 |
52 |
53 |
54 | Autofac.Example.Calculator.Addition.Add, Autofac.Example.Calculator.Addition
55 |
56 | true
57 |
58 |
59 | Autofac.Example.Calculator.Division.Divide, Autofac.Example.Calculator.Division
60 |
61 | true
62 |
63 | 4
64 |
65 |
66 |
67 | ```
68 |
69 | *Note the ordinal "naming" of components and services in XML - this is due to the way Microsoft.Extensions.Configuration handles ordinal collections (arrays).*
70 |
71 | Build up your configuration and register it with the Autofac `ContainerBuilder` like this:
72 |
73 | ```c#
74 | // Add the configuration to the ConfigurationBuilder.
75 | var config = new ConfigurationBuilder();
76 | // config.AddJsonFile comes from Microsoft.Extensions.Configuration.Json
77 | // config.AddXmlFile comes from Microsoft.Extensions.Configuration.Xml
78 | config.AddJsonFile("autofac.json");
79 |
80 | // Register the ConfigurationModule with Autofac.
81 | var module = new ConfigurationModule(config.Build());
82 | var builder = new ContainerBuilder();
83 | builder.RegisterModule(module);
84 | ```
85 |
86 | Check out the [Autofac configuration documentation](https://autofac.readthedocs.io/en/latest/configuration/xml.html) for more information.
87 |
88 | ## Get Help
89 |
90 | **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).
91 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | image: Ubuntu
2 |
3 | version: 7.0.0.{build}
4 |
5 | dotnet_csproj:
6 | version_prefix: '7.0.0'
7 | patch: true
8 | file: 'src\**\*.csproj'
9 |
10 | configuration: Release
11 |
12 | environment:
13 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
14 | NUGET_XMLDOC_MODE: skip
15 |
16 | skip_tags: true
17 |
18 | nuget:
19 | disable_publish_on_pr: true
20 |
21 | clone_depth: 1
22 |
23 | test: false
24 |
25 | build_script:
26 | - pwsh: .\build.ps1
27 |
28 | artifacts:
29 | - path: artifacts\packages\**\*.*nupkg
30 | name: MyGet
31 | type: NuGetPackage
32 |
33 | deploy:
34 | - provider: NuGet
35 | server: https://www.myget.org/F/autofac/api/v2/package
36 | symbol_server: https://www.myget.org/F/autofac/api/v2/package
37 | api_key:
38 | secure: xUXExgVAagrdEicCjSxsQVrwiLo2TtnfqMbYB9Cauq2cpbm/EVz957PBK0v/GEYq
39 | artifact: MyGet
40 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | ########################
2 | # THE BUILD!
3 | ########################
4 |
5 | Push-Location $PSScriptRoot
6 | try {
7 | Import-Module $PSScriptRoot/build/Autofac.Build.psd1 -Force
8 |
9 | $artifactsPath = "$PSScriptRoot/artifacts"
10 | $packagesPath = "$artifactsPath/packages"
11 |
12 | $globalJson = (Get-Content "$PSScriptRoot/global.json" | ConvertFrom-Json -NoEnumerate);
13 |
14 | $sdkVersion = $globalJson.sdk.version
15 |
16 | # Clean up artifacts folder
17 | if (Test-Path $artifactsPath) {
18 | Write-Message "Cleaning $artifactsPath folder"
19 | Remove-Item $artifactsPath -Force -Recurse
20 | }
21 |
22 | # Install dotnet SDK versions during CI. In a local build we assume you have
23 | # everything installed; on CI we'll force the install. If you install _any_
24 | # SDKs, you have to install _all_ of them because you can't install SDKs in
25 | # two different locations. dotnet CLI locates SDKs relative to the
26 | # executable.
27 | if ($Null -ne $env:APPVEYOR_BUILD_NUMBER) {
28 | Install-DotNetCli -Version $sdkVersion
29 | foreach ($additional in $globalJson.additionalSdks)
30 | {
31 | Install-DotNetCli -Version $additional;
32 | }
33 | }
34 |
35 | # Write out dotnet information
36 | & dotnet --info
37 |
38 | # Set version suffix
39 | $branch = @{ $true = $env:APPVEYOR_REPO_BRANCH; $false = $(git symbolic-ref --short -q HEAD) }[$NULL -ne $env:APPVEYOR_REPO_BRANCH];
40 | $revision = @{ $true = "{0:00000}" -f [convert]::ToInt32("0" + $env:APPVEYOR_BUILD_NUMBER, 10); $false = "local" }[$NULL -ne $env:APPVEYOR_BUILD_NUMBER];
41 | $versionSuffix = @{ $true = ""; $false = "$($branch.Substring(0, [math]::Min(10,$branch.Length)).Replace('/', '-'))-$revision" }[$branch -eq "master" -and $revision -ne "local"]
42 |
43 | Write-Message "Package version suffix is '$versionSuffix'"
44 |
45 | # Package restore
46 | Write-Message "Restoring packages"
47 | Get-DotNetProjectDirectory -RootPath $PSScriptRoot | Restore-DependencyPackages
48 |
49 | # Build/package
50 | Write-Message "Building projects and packages"
51 | Get-DotNetProjectDirectory -RootPath $PSScriptRoot\src | Invoke-DotNetPack -PackagesPath $packagesPath -VersionSuffix $versionSuffix
52 |
53 | # Test
54 | Write-Message "Executing unit tests"
55 | Get-DotNetProjectDirectory -RootPath $PSScriptRoot\test | Invoke-Test
56 |
57 |
58 | if ($env:CI -eq "true") {
59 | # Generate Coverage Report
60 | Write-Message "Downloading and verifying Codecov Uploader"
61 | $ProgressPreference = 'SilentlyContinue'
62 | Invoke-WebRequest -Uri https://keybase.io/codecovsecurity/pgp_keys.asc -OutFile codecov.asc
63 | gpg --no-default-keyring --keyring trustedkeys.gpg --import codecov.asc
64 | Invoke-WebRequest -Uri https://uploader.codecov.io/latest/linux/codecov -Outfile codecov
65 | Invoke-WebRequest -Uri https://uploader.codecov.io/latest/linux/codecov.SHA256SUM -Outfile codecov.SHA256SUM
66 | Invoke-WebRequest -Uri https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig -Outfile codecov.SHA256SUM.sig
67 | gpgv codecov.SHA256SUM.sig codecov.SHA256SUM
68 | shasum -a 256 -c codecov.SHA256SUM
69 | chmod +x codecov
70 |
71 | Write-Message "Generating Codecov Report"
72 | & ./codecov -f "artifacts/coverage/*/coverage*.info"
73 | }
74 |
75 | # Finished
76 | Write-Message "Build finished"
77 | }
78 | finally {
79 | Pop-Location
80 | }
81 |
--------------------------------------------------------------------------------
/build/Analyzers.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/build/Autofac.Build.psd1:
--------------------------------------------------------------------------------
1 | @{
2 | RootModule = '.\Autofac.Build.psm1'
3 | ModuleVersion = '0.3.0'
4 | GUID = '55d3f738-f48f-4497-9b2c-ecd90ec1f978'
5 | Author = 'Autofac Contributors'
6 | CompanyName = 'Autofac'
7 | Description = 'Build support for Autofac projects.'
8 | FunctionsToExport = '*'
9 | CmdletsToExport = '*'
10 | VariablesToExport = '*'
11 | AliasesToExport = '*'
12 | ModuleList = @()
13 | FileList = @()
14 | PrivateData = ''
15 | }
--------------------------------------------------------------------------------
/build/Autofac.Build.psm1:
--------------------------------------------------------------------------------
1 | # EXIT CODES
2 | # 1: dotnet packaging failure
3 | # 2: dotnet publishing failure
4 | # 3: Unit test failure
5 | # 4: dotnet / NuGet package restore failure
6 |
7 | <#
8 | .SYNOPSIS
9 | Gets the set of directories in which projects are available for compile/processing.
10 |
11 | .PARAMETER RootPath
12 | Path where searching for project directories should begin.
13 | #>
14 | function Get-DotNetProjectDirectory {
15 | [CmdletBinding()]
16 | Param(
17 | [Parameter(Mandatory = $True, ValueFromPipeline = $False, ValueFromPipelineByPropertyName = $False)]
18 | [ValidateNotNullOrEmpty()]
19 | [string]
20 | $RootPath
21 | )
22 |
23 | Get-ChildItem -Path $RootPath -Recurse -Include "*.csproj" | Select-Object @{ Name = "ParentFolder"; Expression = { $_.Directory.FullName.TrimEnd("\") } } | Select-Object -ExpandProperty ParentFolder
24 | }
25 |
26 | <#
27 | .SYNOPSIS
28 | Runs the dotnet CLI install script from GitHub to install a project-local
29 | copy of the CLI.
30 | #>
31 | function Install-DotNetCli {
32 | [CmdletBinding()]
33 | Param(
34 | [string]
35 | $Version = "Latest"
36 | )
37 | Write-Message "Installing .NET SDK version $Version"
38 |
39 | $callerPath = Split-Path $MyInvocation.PSCommandPath
40 | $installDir = Join-Path -Path $callerPath -ChildPath ".dotnet/cli"
41 | if (!(Test-Path $installDir)) {
42 | New-Item -ItemType Directory -Path "$installDir" | Out-Null
43 | }
44 |
45 | # Download the dotnet CLI install script
46 | if ($IsWindows) {
47 | if (!(Test-Path ./.dotnet/dotnet-install.ps1)) {
48 | Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile "./.dotnet/dotnet-install.ps1"
49 | }
50 |
51 | & ./.dotnet/dotnet-install.ps1 -InstallDir "$installDir" -Version $Version
52 | } else {
53 | if (!(Test-Path ./.dotnet/dotnet-install.sh)) {
54 | Invoke-WebRequest "https://dot.net/v1/dotnet-install.sh" -OutFile "./.dotnet/dotnet-install.sh"
55 | }
56 |
57 | & bash ./.dotnet/dotnet-install.sh --install-dir "$installDir" --version $Version
58 | }
59 |
60 | Add-Path "$installDir"
61 | }
62 |
63 | <#
64 | .SYNOPSIS
65 | Appends a given value to the path but only if the value does not yet exist within the path.
66 | .PARAMETER Path
67 | The path to append.
68 | #>
69 | function Add-Path {
70 | [CmdletBinding()]
71 | Param(
72 | [ValidateNotNullOrEmpty()]
73 | [string]
74 | $Path
75 | )
76 |
77 | $pathSeparator = ":";
78 |
79 | if ($IsWindows) {
80 | $pathSeparator = ";";
81 | }
82 |
83 | $pathValues = $env:PATH.Split($pathSeparator);
84 | if ($pathValues -Contains $Path) {
85 | return;
86 | }
87 |
88 | $env:PATH = "${Path}${pathSeparator}$env:PATH"
89 | }
90 |
91 | <#
92 | .SYNOPSIS
93 | Builds a project using dotnet cli.
94 | .DESCRIPTION
95 | Builds a project in a specified directory using the dotnet cli.
96 | .PARAMETER DirectoryName
97 | The path to the directory containing the project to build.
98 | #>
99 | function Invoke-DotNetBuild {
100 | [CmdletBinding()]
101 | Param(
102 | [Parameter(Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
103 | [ValidateNotNull()]
104 | [System.IO.DirectoryInfo[]]
105 | $ProjectDirectory
106 | )
107 | Process {
108 | foreach ($Project in $ProjectDirectory) {
109 | & dotnet build ("""" + $Project.FullName + """") --configuration Release
110 | if ($LASTEXITCODE -ne 0) {
111 | exit 1
112 | }
113 | }
114 | }
115 | }
116 |
117 | <#
118 | .SYNOPSIS
119 | Invokes the dotnet utility to package a project.
120 |
121 | .PARAMETER ProjectDirectory
122 | Path to the directory containing the project to package.
123 |
124 | .PARAMETER PackagesPath
125 | Path to the "artifacts/packages" folder where packages should go.
126 |
127 | .PARAMETER VersionSuffix
128 | The version suffix to use for the NuGet package version.
129 | #>
130 | function Invoke-DotNetPack {
131 | [CmdletBinding()]
132 | Param(
133 | [Parameter(Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
134 | [ValidateNotNull()]
135 | [System.IO.DirectoryInfo[]]
136 | $ProjectDirectory,
137 |
138 | [Parameter(Mandatory = $True, ValueFromPipeline = $False)]
139 | [ValidateNotNull()]
140 | [System.IO.DirectoryInfo]
141 | $PackagesPath,
142 |
143 | [Parameter(Mandatory = $True, ValueFromPipeline = $False)]
144 | [AllowEmptyString()]
145 | [string]
146 | $VersionSuffix
147 | )
148 | Begin {
149 | New-Item -Path $PackagesPath -ItemType Directory -Force | Out-Null
150 | }
151 | Process {
152 | foreach ($Project in $ProjectDirectory) {
153 | if ($VersionSuffix -eq "") {
154 | & dotnet build ("""" + $Project.FullName + """") --configuration Release
155 | }
156 | else {
157 | & dotnet build ("""" + $Project.FullName + """") --configuration Release --version-suffix $VersionSuffix
158 | }
159 | if ($LASTEXITCODE -ne 0) {
160 | exit 1
161 | }
162 |
163 | if ($VersionSuffix -eq "") {
164 | & dotnet pack ("""" + $Project.FullName + """") --configuration Release --output $PackagesPath
165 | }
166 | else {
167 | & dotnet pack ("""" + $Project.FullName + """") --configuration Release --version-suffix $VersionSuffix --output $PackagesPath
168 | }
169 | if ($LASTEXITCODE -ne 0) {
170 | exit 1
171 | }
172 | }
173 | }
174 | }
175 |
176 | <#
177 | .SYNOPSIS
178 | Invokes dotnet test command.
179 |
180 | .PARAMETER ProjectDirectory
181 | Path to the directory containing the project to package.
182 | #>
183 | function Invoke-Test {
184 | [CmdletBinding()]
185 | Param(
186 | [Parameter(Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
187 | [ValidateNotNull()]
188 | [System.IO.DirectoryInfo[]]
189 | $ProjectDirectory
190 | )
191 | Process {
192 | foreach ($Project in $ProjectDirectory) {
193 | Push-Location $Project
194 |
195 | & dotnet test `
196 | --configuration Release `
197 | --logger:trx `
198 | /p:CollectCoverage=true `
199 | /p:CoverletOutput="../../artifacts/coverage/$($Project.Name)/" `
200 | /p:CoverletOutputFormat="json%2clcov" `
201 | /p:ExcludeByAttribute=CompilerGeneratedAttribute `
202 | /p:ExcludeByAttribute=GeneratedCodeAttribute
203 |
204 | if ($LASTEXITCODE -ne 0) {
205 | Pop-Location
206 | exit 3
207 | }
208 |
209 | Pop-Location
210 | }
211 | }
212 | }
213 |
214 | <#
215 | .SYNOPSIS
216 | Restores dependencies using the dotnet utility.
217 |
218 | .PARAMETER ProjectDirectory
219 | Path to the directory containing the project with dependencies to restore.
220 | #>
221 | function Restore-DependencyPackages {
222 | [CmdletBinding()]
223 | Param(
224 | [Parameter(Mandatory = $True, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
225 | [ValidateNotNull()]
226 | [System.IO.DirectoryInfo[]]
227 | $ProjectDirectory
228 | )
229 | Process {
230 | foreach ($Project in $ProjectDirectory) {
231 | & dotnet restore ("""" + $Project.FullName + """") --no-cache
232 | if ($LASTEXITCODE -ne 0) {
233 | exit 4
234 | }
235 | }
236 | }
237 | }
238 |
239 | <#
240 | .SYNOPSIS
241 | Writes a build progress message to the host.
242 |
243 | .PARAMETER Message
244 | The message to write.
245 | #>
246 | function Write-Message {
247 | [CmdletBinding()]
248 | Param(
249 | [Parameter(Mandatory = $True, ValueFromPipeline = $False, ValueFromPipelineByPropertyName = $False)]
250 | [ValidateNotNullOrEmpty()]
251 | [string]
252 | $Message
253 | )
254 |
255 | Write-Host "[BUILD] $Message" -ForegroundColor Cyan
256 | }
257 |
--------------------------------------------------------------------------------
/build/Test.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/build/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/autofac/Autofac.Configuration/4fff3f5b19ec62bc6cb995bd5c15f4fac8c2c0f9/build/icon.png
--------------------------------------------------------------------------------
/build/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
3 | "settings": {
4 | "documentationRules": {
5 | "companyName": "Autofac Project",
6 | "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} License. See {licenseFile} in the project root for license information.",
7 | "variables": {
8 | "licenseFile": "LICENSE",
9 | "licenseName": "MIT"
10 | },
11 | "xmlHeader": false
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | codecov:
2 | branch: develop
3 | require_ci_to_pass: yes
4 | coverage:
5 | status:
6 | project:
7 | default:
8 | threshold: 1%
9 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "8.0.204",
4 | "rollForward": "latestFeature"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Autofac.Configuration.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 0.0.1
5 |
6 | Autofac.Configuration
7 | Autofac.Configuration
8 | Configuration support for Autofac.
9 | Copyright © 2015 Autofac Contributors
10 | Autofac Contributors
11 | Autofac
12 | Autofac
13 | ../../Autofac.snk
14 | true
15 | en-US
16 |
17 | netstandard2.1;netstandard2.0
18 | latest
19 | enable
20 | true
21 | ../../build/Analyzers.ruleset
22 | true
23 | AllEnabledByDefault
24 | enable
25 |
26 | Autofac.Configuration
27 | autofac;di;ioc;dependencyinjection
28 | Release notes are at https://github.com/autofac/Autofac.Configuration/releases
29 | icon.png
30 | https://autofac.org
31 | MIT
32 | README.md
33 | git
34 | https://github.com/autofac/Autofac.Configuration
35 | true
36 | true
37 | true
38 | true
39 | snupkg
40 |
41 | PrepareResources;$(CompileDependsOn)
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | $(NoWarn);8600;8601;8602;8603;8604
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | all
68 |
69 |
70 | all
71 |
72 |
73 |
74 |
75 |
76 | MSBuild:Compile
77 | CSharp
78 | $(IntermediateOutputPath)%(Filename).Designer.cs
79 | %(Filename)
80 |
81 |
82 |
83 |
84 |
85 | Autofac.Configuration
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/ConfigurationModule.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using Autofac.Configuration.Core;
5 | using Microsoft.Extensions.Configuration;
6 |
7 | namespace Autofac.Configuration;
8 |
9 | ///
10 | /// Module for configuration parsing and registration.
11 | ///
12 | public class ConfigurationModule : Module
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | ///
18 | /// An containing the definition for
19 | /// modules and components to register with the container.
20 | ///
21 | ///
22 | /// Thrown if is .
23 | ///
24 | public ConfigurationModule(IConfiguration configuration)
25 | {
26 | Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
27 | }
28 |
29 | ///
30 | /// Gets the configuration to register.
31 | ///
32 | ///
33 | /// An containing the definition for
34 | /// modules and components to register with the container.
35 | ///
36 | public IConfiguration Configuration { get; private set; }
37 |
38 | ///
39 | /// Gets or sets the configuration registrar.
40 | ///
41 | ///
42 | /// An that will be used as the
43 | /// strategy for converting the
44 | /// into component registrations. If this value is , the registrar
45 | /// will be a .
46 | ///
47 | public IConfigurationRegistrar? ConfigurationRegistrar { get; set; }
48 |
49 | ///
50 | /// Executes the conversion of configuration data into component registrations.
51 | ///
52 | ///
53 | /// The into which registrations will be placed.
54 | ///
55 | ///
56 | ///
57 | /// This override uses the
58 | /// to convert the
59 | /// into component registrations in the provided .
60 | ///
61 | ///
62 | /// If no specific
63 | /// is set, the default type will be used.
64 | ///
65 | ///
66 | ///
67 | /// Thrown if is .
68 | ///
69 | protected override void Load(ContainerBuilder builder)
70 | {
71 | if (builder == null)
72 | {
73 | throw new ArgumentNullException(nameof(builder));
74 | }
75 |
76 | var registrar = ConfigurationRegistrar ?? new ConfigurationRegistrar();
77 | registrar.RegisterConfiguration(builder, Configuration);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/ConfigurationResources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | The {0} may not be empty.
122 |
123 |
124 | The '{0}' collection should be ordinal (like an array) with items that have numeric names to indicate the index in the collection. '{1}' didn't have a numeric name so couldn't be parsed. Check https://autofac.readthedocs.io/en/latest/configuration/xml.html for configuration examples.
125 |
126 |
127 | Key cannot be null or empty in a dictionary parameter.
128 |
129 |
130 | No constructors on type '{0}' can be found. Make sure your type has at least one public constructor.
131 |
132 |
133 | If 'name' is specified, 'service' must also be specified (component name='{0}'.)
134 |
135 |
136 | Unable to convert object of type '{0}' to type '{1}'.
137 |
138 |
139 | The type '{0}' specified in the TypeConverterAttribute is not a TypeConverter.
140 |
141 |
142 | The type '{0}' could not be found. It may require assembly qualification, e.g. "MyType, MyAssembly".
143 |
144 |
145 | The value '{0}' is not valid for a Boolean setting. Valid values are 'true' and 'false'.
146 |
147 |
148 | The value '{0}' is not valid for the ownership setting. Valid values are 'lifetime-scope' (the default) and 'external'.
149 |
150 |
151 | The value '{0}' is not valid for the instance scope setting. Valid values are 'single-instance', 'per-dependency' (the default), 'per-lifetime-scope', and 'per-request'.
152 |
153 |
154 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Core/ConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using System.Globalization;
5 | using System.Reflection;
6 | using Autofac.Configuration.Util;
7 | using Autofac.Core;
8 | using Microsoft.Extensions.Configuration;
9 |
10 | namespace Autofac.Configuration.Core;
11 |
12 | ///
13 | /// Extension methods for working with .
14 | ///
15 | public static class ConfigurationExtensions
16 | {
17 | ///
18 | /// Reads the default assembly information from configuration and
19 | /// parses the assembly name into an assembly.
20 | ///
21 | ///
22 | /// An from which the default assembly
23 | /// should be read.
24 | ///
25 | ///
26 | /// An if the default assembly is specified on
27 | /// ; or if not.
28 | ///
29 | ///
30 | /// Thrown if is .
31 | ///
32 | public static Assembly? DefaultAssembly(this IConfiguration configuration)
33 | {
34 | return configuration.GetAssembly("defaultAssembly");
35 | }
36 |
37 | ///
38 | /// Reads an assembly name from configuration and parses the assembly name into an assembly.
39 | ///
40 | ///
41 | /// An from which the default assembly
42 | /// should be read.
43 | ///
44 | ///
45 | /// The key in configuration where the assembly name
46 | /// is specified.
47 | ///
48 | ///
49 | /// An if the assembly is specified on
50 | /// ; or if not.
51 | ///
52 | ///
53 | /// Thrown if or is .
54 | ///
55 | ///
56 | /// Thrown if is empty or whitespace.
57 | ///
58 | public static Assembly? GetAssembly(this IConfiguration configuration, string key)
59 | {
60 | if (configuration == null)
61 | {
62 | throw new ArgumentNullException(nameof(configuration));
63 | }
64 |
65 | if (key == null)
66 | {
67 | throw new ArgumentNullException(nameof(key));
68 | }
69 |
70 | if (string.IsNullOrWhiteSpace(key))
71 | {
72 | throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ConfigurationResources.ArgumentMayNotBeEmpty, "configuration key"), nameof(key));
73 | }
74 |
75 | var assemblyName = configuration[key];
76 | return string.IsNullOrWhiteSpace(assemblyName) ? null : Assembly.Load(new AssemblyName(assemblyName));
77 | }
78 |
79 | ///
80 | /// Converts configured parameter values into parameters that can be used
81 | /// during object resolution.
82 | ///
83 | ///
84 | /// The element that contains the component
85 | /// with defined parameters.
86 | ///
87 | ///
88 | /// The key indicating the sub-element with the
89 | /// parameters. Usually this is parameters.
90 | ///
91 | ///
92 | /// An of values
93 | /// that can be used during object resolution.
94 | ///
95 | public static IEnumerable GetParameters(this IConfiguration configuration, string key)
96 | {
97 | if (configuration == null)
98 | {
99 | throw new ArgumentNullException(nameof(configuration));
100 | }
101 |
102 | if (key == null)
103 | {
104 | throw new ArgumentNullException(nameof(key));
105 | }
106 |
107 | if (string.IsNullOrWhiteSpace(key))
108 | {
109 | throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ConfigurationResources.ArgumentMayNotBeEmpty, "configuration key"), nameof(key));
110 | }
111 |
112 | foreach (var parameterElement in configuration.GetSection(key).GetChildren())
113 | {
114 | var parameterValue = GetConfiguredParameterValue(parameterElement);
115 | string parameterName = GetKeyName(parameterElement.Key);
116 | yield return new ResolvedParameter(
117 | (pi, c) => string.Equals(pi.Name, parameterName, StringComparison.OrdinalIgnoreCase),
118 | (pi, c) => TypeManipulation.ChangeToCompatibleType(parameterValue, pi.ParameterType, pi));
119 | }
120 | }
121 |
122 | ///
123 | /// Converts configured property values into parameters that can be used
124 | /// during object resolution.
125 | ///
126 | ///
127 | /// The element that contains the component
128 | /// with defined properties.
129 | ///
130 | ///
131 | /// The key indicating the sub-element with the
132 | /// properties. Usually this is properties.
133 | ///
134 | ///
135 | /// An of values
136 | /// that can be used during object resolution.
137 | ///
138 | public static IEnumerable GetProperties(this IConfiguration configuration, string key)
139 | {
140 | if (configuration == null)
141 | {
142 | throw new ArgumentNullException(nameof(configuration));
143 | }
144 |
145 | if (key == null)
146 | {
147 | throw new ArgumentNullException(nameof(key));
148 | }
149 |
150 | if (string.IsNullOrWhiteSpace(key))
151 | {
152 | throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ConfigurationResources.ArgumentMayNotBeEmpty, "configuration key"), nameof(key));
153 | }
154 |
155 | foreach (var propertyElement in configuration.GetSection(key).GetChildren())
156 | {
157 | var parameterValue = GetConfiguredParameterValue(propertyElement);
158 | string parameterName = GetKeyName(propertyElement.Key);
159 | yield return new ResolvedParameter(
160 | (pi, c) =>
161 | {
162 | return pi.TryGetDeclaringProperty(out PropertyInfo? prop) &&
163 | string.Equals(prop.Name, parameterName, StringComparison.OrdinalIgnoreCase);
164 | },
165 | (pi, c) =>
166 | {
167 | pi.TryGetDeclaringProperty(out PropertyInfo? prop);
168 | return TypeManipulation.ChangeToCompatibleType(parameterValue, pi.ParameterType, prop!);
169 | });
170 | }
171 | }
172 |
173 | ///
174 | /// Loads a type by name.
175 | ///
176 | ///
177 | /// The object containing the type value to load.
178 | ///
179 | ///
180 | /// Name of the to load. This may be a partial type name or a fully-qualified type name.
181 | ///
182 | ///
183 | /// The default to use in type resolution if
184 | /// is a partial type name.
185 | ///
186 | ///
187 | /// The resolved based on the specified name.
188 | ///
189 | ///
190 | /// Thrown if is .
191 | ///
192 | ///
193 | /// Thrown if the specified can't be resolved as a fully-qualified type name and
194 | /// isn't a partial type name for a found in the .
195 | ///
196 | public static Type GetType(this IConfiguration configuration, string key, Assembly? defaultAssembly)
197 | {
198 | if (configuration == null)
199 | {
200 | throw new ArgumentNullException(nameof(configuration));
201 | }
202 |
203 | var typeName = configuration[key];
204 | var type = Type.GetType(typeName);
205 |
206 | if (type == null && defaultAssembly != null)
207 | {
208 | // Don't throw on error; we'll check it later.
209 | type = defaultAssembly.GetType(typeName, false, true);
210 | }
211 |
212 | return type ?? throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ConfigurationResources.TypeNotFound, typeName));
213 | }
214 |
215 | ///
216 | /// Gets an ordered list of child configuration sections.
217 | ///
218 | /// The configuration item containing the list.
219 | /// The subsection from which to get the ordered list of children.
220 | /// The desired list of configuration subsections.
221 | ///
222 | /// Thrown if or is .
223 | ///
224 | ///
225 | /// Thrown if any of the subsections lack an integer-valued .
226 | ///
227 | internal static IEnumerable GetOrderedSubsections(this IConfiguration configuration, string key)
228 | {
229 | var configurationSection = configuration.GetSection(key);
230 | foreach (var section in configurationSection.GetChildren())
231 | {
232 | yield return int.TryParse(section.Key, out var _)
233 | ? section
234 | : throw new InvalidOperationException(string.Format(ConfigurationResources.CollectionMustBeOrderedByName, key, configurationSection.Path));
235 | }
236 | }
237 |
238 | ///
239 | /// Inspects a parameter/property value to determine if it's a scalar,
240 | /// list, or dictionary property and casts it appropriately.
241 | ///
242 | ///
243 | /// The object containing the parameter/property
244 | /// value to parse.
245 | ///
246 | ///
247 | /// A value that can be type-converted and used during object resolution.
248 | ///
249 | ///
250 | ///
251 | /// The Microsoft configuration model code sees arrays (lists) the same
252 | /// as a dictionary with numeric keys. We have to do some work to determine
253 | /// how to store the parsed configuration values so they can be converted
254 | /// appropriately at resolve time; and there's still an edge case where
255 | /// someone actually wanted a with
256 | /// sequential, zero-based numeric keys.
257 | ///
258 | ///
259 | private static object? GetConfiguredParameterValue(IConfigurationSection value)
260 | {
261 | Tuple[] subKeys = value.GetChildren().Select(sk => new Tuple(GetKeyName(sk.Key), sk.Value)).ToArray();
262 | if (subKeys.Length == 0)
263 | {
264 | // No sub-keys indicates a scalar value.
265 | return value.Value;
266 | }
267 |
268 | if (subKeys.All(sk => int.TryParse(sk.Item1, out int parsed)))
269 | {
270 | int i = 0;
271 | bool isList = true;
272 | foreach (int subKey in subKeys.Select(sk => int.Parse(sk.Item1, CultureInfo.InvariantCulture)))
273 | {
274 | if (subKey != i)
275 | {
276 | isList = false;
277 | break;
278 | }
279 |
280 | i++;
281 | }
282 |
283 | if (isList)
284 | {
285 | var list = new List();
286 | foreach (var subKey in subKeys.Where(s => s.Item2 is not null))
287 | {
288 | list.Add(subKey.Item2!);
289 | }
290 |
291 | return new ConfiguredListParameter { List = list.ToArray() };
292 | }
293 | }
294 |
295 | // There are sub-keys but not all zero-based sequential numbers - it's a dictionary.
296 | var dict = new Dictionary();
297 | foreach (var subKey in subKeys.Where(s => s.Item2 is not null))
298 | {
299 | dict[subKey.Item1] = subKey.Item2!;
300 | }
301 |
302 | return new ConfiguredDictionaryParameter { Dictionary = dict };
303 | }
304 |
305 | ///
306 | /// Gets the simple configuration key name from a full, colon-delimited
307 | /// configuration key name.
308 | ///
309 | /// The full configuration key name, like configuration:full:key.
310 | ///
311 | /// The last segment in the colon-delimited full key name, like key.
312 | ///
313 | private static string GetKeyName(string fullKey)
314 | {
315 | int index = fullKey.LastIndexOf(':');
316 | return index < 0 ? fullKey : fullKey.Substring(index + 1);
317 | }
318 | }
319 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Core/ConfigurationRegistrar.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using Microsoft.Extensions.Configuration;
5 |
6 | namespace Autofac.Configuration.Core;
7 |
8 | ///
9 | /// Default service for adding configured registrations to a container.
10 | ///
11 | ///
12 | ///
13 | /// This default implementation of
14 | /// processes contents into registrations for
15 | /// a . You may derive and override to extend the functionality
16 | /// or you may implement your own .
17 | ///
18 | ///
19 | ///
20 | public class ConfigurationRegistrar : IConfigurationRegistrar
21 | {
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | public ConfigurationRegistrar()
26 | : this(new ComponentRegistrar(), new ModuleRegistrar())
27 | {
28 | }
29 |
30 | ///
31 | /// Initializes a new instance of the class.
32 | ///
33 | ///
34 | /// The that will be used to parse
35 | /// configuration values into component registrations.
36 | ///
37 | ///
38 | /// The that will be used to parse
39 | /// configuration values into module registrations.
40 | ///
41 | ///
42 | /// Thrown if or is .
43 | ///
44 | public ConfigurationRegistrar(IComponentRegistrar componentRegistrar, IModuleRegistrar moduleRegistrar)
45 | {
46 | ComponentRegistrar = componentRegistrar ?? throw new ArgumentNullException(nameof(componentRegistrar));
47 | ModuleRegistrar = moduleRegistrar ?? throw new ArgumentNullException(nameof(moduleRegistrar));
48 | }
49 |
50 | ///
51 | /// Gets the component registration parser.
52 | ///
53 | ///
54 | /// The that will be used to parse
55 | /// configuration values into component registrations.
56 | ///
57 | public IComponentRegistrar ComponentRegistrar { get; private set; }
58 |
59 | ///
60 | /// Gets the module registration parser.
61 | ///
62 | ///
63 | /// The that will be used to parse
64 | /// configuration values into module registrations.
65 | ///
66 | public IModuleRegistrar ModuleRegistrar { get; private set; }
67 |
68 | ///
69 | /// Registers the contents of a configuration section into a container builder.
70 | ///
71 | ///
72 | /// The that should receive the configured registrations.
73 | ///
74 | ///
75 | /// The containing the configured registrations.
76 | ///
77 | ///
78 | /// Thrown if or is .
79 | ///
80 | ///
81 | ///
82 | /// This method is the primary entry point to configuration section registration. From here,
83 | /// the various modules, components, and referenced files get registered. You may override
84 | /// any of those behaviors for a custom registrar if you wish to extend registration behavior.
85 | ///
86 | ///
87 | public virtual void RegisterConfiguration(ContainerBuilder builder, IConfiguration configuration)
88 | {
89 | if (builder == null)
90 | {
91 | throw new ArgumentNullException(nameof(builder));
92 | }
93 |
94 | if (configuration == null)
95 | {
96 | throw new ArgumentNullException(nameof(configuration));
97 | }
98 |
99 | ModuleRegistrar.RegisterConfiguredModules(builder, configuration);
100 | ComponentRegistrar.RegisterConfiguredComponents(builder, configuration);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Core/ModuleRegistrar.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using System.Reflection;
5 | using Autofac.Core;
6 | using Autofac.Core.Activators.Reflection;
7 | using Microsoft.Extensions.Configuration;
8 |
9 | namespace Autofac.Configuration.Core;
10 |
11 | ///
12 | /// Default module configuration processor.
13 | ///
14 | ///
15 | public class ModuleRegistrar : IModuleRegistrar
16 | {
17 | ///
18 | /// Registers individual configured modules into a container builder.
19 | ///
20 | ///
21 | /// The that should receive the configured registrations.
22 | ///
23 | ///
24 | /// The containing the configured registrations.
25 | ///
26 | ///
27 | /// Thrown if or is .
28 | ///
29 | ///
30 | /// Thrown if there is any issue in parsing the module configuration into registrations.
31 | ///
32 | ///
33 | ///
34 | /// This is where the individually configured component registrations get added to the .
35 | /// The modules collection from the
36 | /// get processed into individual modules which are instantiated and activated inside the .
37 | ///
38 | ///
39 | public virtual void RegisterConfiguredModules(ContainerBuilder builder, IConfiguration configuration)
40 | {
41 | if (builder == null)
42 | {
43 | throw new ArgumentNullException(nameof(builder));
44 | }
45 |
46 | if (configuration == null)
47 | {
48 | throw new ArgumentNullException(nameof(configuration));
49 | }
50 |
51 | var defaultAssembly = configuration.DefaultAssembly();
52 | foreach (var moduleElement in configuration.GetOrderedSubsections("modules"))
53 | {
54 | var moduleType = moduleElement.GetType("type", defaultAssembly);
55 |
56 | var module = CreateModule(moduleType, moduleElement);
57 |
58 | builder.RegisterModule(module);
59 | }
60 | }
61 |
62 | private static IModule CreateModule(Type type, IConfiguration moduleElement)
63 | {
64 | var parametersElement = moduleElement.GetSection("parameters");
65 | var parameterNames = parametersElement.GetChildren().Select(section => section.Key);
66 |
67 | var constructorFinder = new DefaultConstructorFinder();
68 | var publicConstructors = constructorFinder.FindConstructors(type);
69 | if (publicConstructors.Length == 0)
70 | {
71 | throw new NoConstructorsFoundException(type, constructorFinder);
72 | }
73 |
74 | var constructor = GetConstructorMatchingParameterNames(publicConstructors, parameterNames) ?? GetMostParametersConstructor(publicConstructors);
75 | var parameters = constructor.GetParameters()
76 | .Select(p => parametersElement.GetSection(p.Name).Get(p.ParameterType))
77 | .ToArray();
78 |
79 | var module = (IModule)constructor.Invoke(parameters);
80 |
81 | var propertiesElement = moduleElement.GetSection("properties");
82 |
83 | propertiesElement.Bind(module);
84 |
85 | return module;
86 | }
87 |
88 | private static ConstructorInfo GetConstructorMatchingParameterNames(ConstructorInfo[] constructors, IEnumerable parameterNames)
89 | {
90 | return constructors.Where(constructorInfo => constructorInfo.GetParameters()
91 | .Select(pInfo => pInfo.Name)
92 | .OrderBy(name => name)
93 | .SequenceEqual(parameterNames.OrderBy(s => s), StringComparer.OrdinalIgnoreCase))
94 | .FirstOrDefault();
95 | }
96 |
97 | private static ConstructorInfo GetMostParametersConstructor(ConstructorInfo[] constructors)
98 | {
99 | return constructors.OrderByDescending(x => x.GetParameters().Length).First();
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/IComponentRegistrar.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using Microsoft.Extensions.Configuration;
5 |
6 | namespace Autofac.Configuration;
7 |
8 | ///
9 | /// Defines a registration mechanism that converts configuration data
10 | /// into Autofac component registrations.
11 | ///
12 | ///
13 | public interface IComponentRegistrar
14 | {
15 | ///
16 | /// Registers individual configured components into a container builder.
17 | ///
18 | ///
19 | /// The that should receive the configured registrations.
20 | ///
21 | ///
22 | /// The containing the configured registrations.
23 | ///
24 | ///
25 | /// Thrown if or is .
26 | ///
27 | ///
28 | /// Thrown if there is any issue in parsing the component configuration into registrations.
29 | ///
30 | ///
31 | ///
32 | /// Implementations of this method are responsible for adding components
33 | /// to the container by parsing configuration model data and executing
34 | /// the registration logic.
35 | ///
36 | ///
37 | void RegisterConfiguredComponents(ContainerBuilder builder, IConfiguration configuration);
38 | }
39 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/IConfigurationRegistrar.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using Microsoft.Extensions.Configuration;
5 |
6 | namespace Autofac.Configuration;
7 |
8 | ///
9 | /// A service for adding configured registrations to a container.
10 | ///
11 | public interface IConfigurationRegistrar
12 | {
13 | ///
14 | /// Registers the contents of a configuration object into a container builder.
15 | ///
16 | ///
17 | /// The that should receive the configured registrations.
18 | ///
19 | ///
20 | /// The containing the configured registrations.
21 | ///
22 | void RegisterConfiguration(ContainerBuilder builder, IConfiguration configuration);
23 | }
24 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/IModuleRegistrar.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using Microsoft.Extensions.Configuration;
5 |
6 | namespace Autofac.Configuration;
7 |
8 | ///
9 | /// Defines a registration mechanism that converts configuration data
10 | /// into Autofac module registrations.
11 | ///
12 | ///
13 | public interface IModuleRegistrar
14 | {
15 | ///
16 | /// Registers individual configured modules into a container builder.
17 | ///
18 | ///
19 | /// The that should receive the configured registrations.
20 | ///
21 | ///
22 | /// The containing the configured registrations.
23 | ///
24 | ///
25 | /// Thrown if or is .
26 | ///
27 | ///
28 | /// Thrown if there is any issue in parsing the module configuration into registrations.
29 | ///
30 | ///
31 | ///
32 | /// Implementations of this method are responsible for adding modules
33 | /// to the container by parsing configuration model data and executing
34 | /// the registration logic.
35 | ///
36 | ///
37 | void RegisterConfiguredModules(ContainerBuilder builder, IConfiguration configuration);
38 | }
39 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/NullableAttributes.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | #pragma warning disable MA0048 // File name must match type name
5 | #pragma warning disable SA1402 // File may only contain a single type
6 | #pragma warning disable SA1649 // File name should match first type name
7 | #if NETSTANDARD2_0
8 |
9 | namespace System.Diagnostics.CodeAnalysis;
10 |
11 | /// Specifies that null is allowed as an input even if the corresponding type disallows it.
12 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
13 | internal sealed class AllowNullAttribute : Attribute
14 | {
15 | }
16 |
17 | /// Specifies that null is disallowed as an input even if the corresponding type allows it.
18 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)]
19 | internal sealed class DisallowNullAttribute : Attribute
20 | {
21 | }
22 |
23 | /// Specifies that an output may be null even if the corresponding type disallows it.
24 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
25 | internal sealed class MaybeNullAttribute : Attribute
26 | {
27 | }
28 |
29 | /// Specifies that an output will not be null even if the corresponding type allows it.
30 | [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)]
31 | internal sealed class NotNullAttribute : Attribute
32 | {
33 | }
34 |
35 | /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it.
36 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
37 | internal sealed class MaybeNullWhenAttribute : Attribute
38 | {
39 | ///
40 | /// Initializes a new instance of the class with the specified return value condition.
41 | ///
42 | ///
43 | /// The return value condition. If the method returns this value, the associated parameter may be null.
44 | ///
45 | public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
46 |
47 | ///
48 | /// Gets a value indicating whether the return value is required to be true or false.
49 | ///
50 | public bool ReturnValue { get; }
51 | }
52 |
53 | /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it.
54 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
55 | internal sealed class NotNullWhenAttribute : Attribute
56 | {
57 | ///
58 | /// Initializes a new instance of the class with the specified return value condition.
59 | ///
60 | /// The return value condition. If the method returns this value, the associated parameter will not be null.
61 | ///
62 | public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue;
63 |
64 | ///
65 | /// Gets a value indicating whether the return value is required to be true or false.
66 | ///
67 | public bool ReturnValue { get; }
68 | }
69 |
70 | /// Specifies that the output will be non-null if the named parameter is non-null.
71 | [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)]
72 | internal sealed class NotNullIfNotNullAttribute : Attribute
73 | {
74 | ///
75 | /// Initializes a new instance of the class with the associated parameter name.
76 | ///
77 | /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null.
78 | ///
79 | public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName;
80 |
81 | ///
82 | /// Gets the name of the parameter.
83 | ///
84 | public string ParameterName { get; }
85 | }
86 |
87 | /// Applied to a method that will never return under any circumstance.
88 | [AttributeUsage(AttributeTargets.Method, Inherited = false)]
89 | internal sealed class DoesNotReturnAttribute : Attribute
90 | {
91 | }
92 |
93 | /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value.
94 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
95 | internal sealed class DoesNotReturnIfAttribute : Attribute
96 | {
97 | ///
98 | /// Initializes a new instance of the class with the specified parameter value.
99 | ///
100 | /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to
101 | /// the associated parameter matches this value.
102 | ///
103 | public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue;
104 |
105 | ///
106 | /// Gets a value indicating whether the parameter value is expected to be true or false.
107 | ///
108 | public bool ParameterValue { get; }
109 | }
110 | #endif
111 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.InteropServices;
6 |
7 | [assembly: InternalsVisibleTo("Autofac.Configuration.Test, PublicKey=00240000048000009400000006020000002400005253413100040000010001008728425885ef385e049261b18878327dfaaf0d666dea3bd2b0e4f18b33929ad4e5fbc9087e7eda3c1291d2de579206d9b4292456abffbe8be6c7060b36da0c33b883e3878eaf7c89fddf29e6e27d24588e81e86f3a22dd7b1a296b5f06fbfb500bbd7410faa7213ef4e2ce7622aefc03169b0324bcd30ccfe9ac8204e4960be6")]
8 | [assembly: ComVisible(false)]
9 | [assembly: CLSCompliant(false)]
10 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Util/ConfiguredDictionaryParameter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using System.Collections;
5 | using System.ComponentModel;
6 | using System.Globalization;
7 |
8 | namespace Autofac.Configuration.Util;
9 |
10 | ///
11 | /// Configuration settings that provide a dictionary parameter to a registration.
12 | ///
13 | [TypeConverter(typeof(DictionaryTypeConverter))]
14 | internal class ConfiguredDictionaryParameter
15 | {
16 | ///
17 | /// Gets or sets the dictionary of raw values.
18 | ///
19 | public Dictionary? Dictionary { get; set; }
20 |
21 | private class DictionaryTypeConverter : TypeConverter
22 | {
23 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
24 | {
25 | var instantiableType = GetInstantiableType(destinationType);
26 |
27 | if (value is ConfiguredDictionaryParameter castValue && instantiableType != null)
28 | {
29 | var dictionary = (IDictionary)Activator.CreateInstance(instantiableType);
30 | var generics = instantiableType.GetGenericArguments();
31 |
32 | if (castValue.Dictionary != null)
33 | {
34 | foreach (var item in castValue.Dictionary)
35 | {
36 | if (string.IsNullOrEmpty(item.Key))
37 | {
38 | throw new FormatException(ConfigurationResources.DictionaryKeyMayNotBeNullOrEmpty);
39 | }
40 |
41 | var convertedKey = TypeManipulation.ChangeToCompatibleType(item.Key, generics[0]);
42 | var convertedValue = TypeManipulation.ChangeToCompatibleType(item.Value, generics[1]);
43 |
44 | dictionary.Add(convertedKey, convertedValue);
45 | }
46 | }
47 |
48 | return dictionary;
49 | }
50 |
51 | return base.ConvertTo(context, culture, value, destinationType);
52 | }
53 |
54 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
55 | {
56 | return GetInstantiableType(destinationType) != null || base.CanConvertTo(context, destinationType);
57 | }
58 |
59 | private static Type? GetInstantiableType(Type destinationType)
60 | {
61 | if (typeof(IDictionary).IsAssignableFrom(destinationType) ||
62 | (destinationType.IsConstructedGenericType && typeof(IDictionary<,>).IsAssignableFrom(destinationType.GetGenericTypeDefinition())))
63 | {
64 | var generics = destinationType.IsConstructedGenericType ? destinationType.GetGenericArguments() : new[] { typeof(string), typeof(object) };
65 | if (generics.Length != 2)
66 | {
67 | return null;
68 | }
69 |
70 | var dictType = typeof(Dictionary<,>).MakeGenericType(generics);
71 | if (destinationType.IsAssignableFrom(dictType))
72 | {
73 | return dictType;
74 | }
75 | }
76 |
77 | return null;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Util/ConfiguredListParameter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using System.Collections;
5 | using System.ComponentModel;
6 |
7 | namespace Autofac.Configuration.Util;
8 |
9 | ///
10 | /// Configuration settings that provide a list parameter to a registration.
11 | ///
12 | [TypeConverter(typeof(ListTypeConverter))]
13 | internal class ConfiguredListParameter
14 | {
15 | ///
16 | /// Gets or sets the list of raw values.
17 | ///
18 | public string[]? List { get; set; }
19 |
20 | private class ListTypeConverter : TypeConverter
21 | {
22 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
23 | {
24 | return GetInstantiableListType(destinationType) != null ||
25 | GetInstantiableDictionaryType(destinationType) != null ||
26 | base.CanConvertTo(context, destinationType);
27 | }
28 |
29 | public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
30 | {
31 | if (value is ConfiguredListParameter castValue)
32 | {
33 | // 99% of the time this type of parameter will be associated
34 | // with an ordinal list - List or T[] sort of thing...
35 | var instantiableType = GetInstantiableListType(destinationType);
36 | if (instantiableType != null)
37 | {
38 | var collection = (IList)Activator.CreateInstance(instantiableType);
39 | if (castValue.List != null)
40 | {
41 | var generics = instantiableType.GetGenericArguments();
42 | foreach (var item in castValue.List)
43 | {
44 | collection.Add(TypeManipulation.ChangeToCompatibleType(item, generics[0]));
45 | }
46 | }
47 |
48 | return collection;
49 | }
50 |
51 | // ...but there is a very small chance this is a Dictionary where
52 | // the keys are all 0-based and ordinal. This clause checks for
53 | // that one edge case. We should only have gotten here if
54 | // ConfigurationExtensions.GetConfiguredParameterValue saw
55 | // a 0-based configuration dictionary.
56 | instantiableType = GetInstantiableDictionaryType(destinationType);
57 | if (instantiableType != null)
58 | {
59 | var dictionary = (IDictionary)Activator.CreateInstance(instantiableType);
60 | if (castValue.List != null)
61 | {
62 | var generics = instantiableType.GetGenericArguments();
63 | for (int i = 0; i < castValue.List.Length; i++)
64 | {
65 | var convertedKey = TypeManipulation.ChangeToCompatibleType(i, generics[0]);
66 | var convertedValue = TypeManipulation.ChangeToCompatibleType(castValue.List[i], generics[1]);
67 |
68 | dictionary.Add(convertedKey, convertedValue);
69 | }
70 | }
71 |
72 | return dictionary;
73 | }
74 | }
75 |
76 | return base.ConvertTo(context, culture, value, destinationType);
77 | }
78 |
79 | ///
80 | /// Handles type determination for the case where the dictionary
81 | /// has numeric/ordinal keys.
82 | ///
83 | ///
84 | /// The type to which the list content should be converted.
85 | ///
86 | ///
87 | /// A dictionary type where the key can be numeric.
88 | ///
89 | private static Type? GetInstantiableDictionaryType(Type destinationType)
90 | {
91 | if (typeof(IDictionary).IsAssignableFrom(destinationType) ||
92 | (destinationType.IsConstructedGenericType && typeof(IDictionary<,>).IsAssignableFrom(destinationType.GetGenericTypeDefinition())))
93 | {
94 | var generics = destinationType.IsConstructedGenericType ? destinationType.GetGenericArguments() : new[] { typeof(int), typeof(object) };
95 | if (generics.Length != 2)
96 | {
97 | return null;
98 | }
99 |
100 | var dictType = typeof(Dictionary<,>).MakeGenericType(generics);
101 | if (destinationType.IsAssignableFrom(dictType))
102 | {
103 | return dictType;
104 | }
105 | }
106 |
107 | return null;
108 | }
109 |
110 | ///
111 | /// Handles type determination list conversion.
112 | ///
113 | ///
114 | /// The type to which the list content should be converted.
115 | ///
116 | ///
117 | /// A list type compatible with the data values.
118 | ///
119 | private static Type? GetInstantiableListType(Type destinationType)
120 | {
121 | if (typeof(IEnumerable).IsAssignableFrom(destinationType))
122 | {
123 | var generics = destinationType.IsConstructedGenericType ? destinationType.GetGenericArguments() : new[] { typeof(object) };
124 | if (generics.Length != 1)
125 | {
126 | return null;
127 | }
128 |
129 | var listType = typeof(List<>).MakeGenericType(generics);
130 |
131 | if (destinationType.IsAssignableFrom(listType))
132 | {
133 | return listType;
134 | }
135 | }
136 |
137 | return null;
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Util/ReflectionExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using System.Reflection;
5 |
6 | namespace Autofac.Configuration.Util;
7 |
8 | ///
9 | /// Extension methods for reflection-related types.
10 | ///
11 | internal static class ReflectionExtensions
12 | {
13 | ///
14 | /// Maps from a property-set-value parameter to the declaring property.
15 | ///
16 | /// Parameter to the property setter.
17 | /// The property info on which the setter is specified.
18 | /// True if the parameter is a property setter.
19 | public static bool TryGetDeclaringProperty(this ParameterInfo pi, [NotNullWhen(true)] out PropertyInfo? prop)
20 | {
21 | var mi = pi.Member as MethodInfo;
22 | if (mi != null && mi.IsSpecialName && mi.Name.StartsWith("set_", StringComparison.Ordinal))
23 | {
24 | prop = mi.DeclaringType.GetProperty(mi.Name.Substring(4));
25 | return true;
26 | }
27 |
28 | prop = null;
29 | return false;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Util/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using System.Globalization;
5 |
6 | namespace Autofac.Configuration.Util;
7 |
8 | ///
9 | /// Extension methods for parsing string values from configuration.
10 | ///
11 | public static class StringExtensions
12 | {
13 | ///
14 | /// Uses a flexible parsing routine to convert a text value into
15 | /// a .
16 | ///
17 | ///
18 | /// The value to parse into a .
19 | ///
20 | ///
21 | /// or based on the
22 | /// content of the .
23 | ///
24 | ///
25 | /// Thrown if can't be parsed into a .
26 | ///
27 | public static bool ToFlexibleBoolean(this string? value)
28 | {
29 | if (string.IsNullOrWhiteSpace(value) ||
30 | value.Equals("false", StringComparison.OrdinalIgnoreCase) ||
31 | value.Equals("no", StringComparison.OrdinalIgnoreCase) ||
32 | value.Equals("n", StringComparison.OrdinalIgnoreCase) ||
33 | value.Equals("0", StringComparison.OrdinalIgnoreCase))
34 | {
35 | return false;
36 | }
37 | else if (value.Equals("true", StringComparison.OrdinalIgnoreCase) ||
38 | value.Equals("yes", StringComparison.OrdinalIgnoreCase) ||
39 | value.Equals("y", StringComparison.OrdinalIgnoreCase) ||
40 | value.Equals("1", StringComparison.OrdinalIgnoreCase))
41 | {
42 | return true;
43 | }
44 |
45 | throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ConfigurationResources.UnrecognizedBoolean, value));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Autofac.Configuration/Util/TypeManipulation.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using System.ComponentModel;
5 | using System.Globalization;
6 | using System.Reflection;
7 |
8 | namespace Autofac.Configuration.Util;
9 |
10 | ///
11 | /// Utilities for converting string configuration values into strongly-typed objects.
12 | ///
13 | internal class TypeManipulation
14 | {
15 | ///
16 | /// Converts an object to a type compatible with a given parameter.
17 | ///
18 | /// The object value to convert.
19 | /// The destination to which should be converted.
20 | /// The parameter for which the is being converted.
21 | ///
22 | /// An of type , converted using
23 | /// type converters specified on if available. If
24 | /// is then the output will be for reference
25 | /// types and the default value for value types.
26 | ///
27 | ///
28 | /// Thrown if conversion of the value fails.
29 | ///
30 | public static object? ChangeToCompatibleType(object? value, Type destinationType, ParameterInfo memberInfo)
31 | {
32 | TypeConverterAttribute? attrib = null;
33 | if (memberInfo != null)
34 | {
35 | attrib = memberInfo.GetCustomAttributes(typeof(TypeConverterAttribute), true).Cast().FirstOrDefault();
36 | }
37 |
38 | return ChangeToCompatibleType(value, destinationType, attrib);
39 | }
40 |
41 | ///
42 | /// Converts an object to a type compatible with a given parameter.
43 | ///
44 | /// The object value to convert.
45 | /// The destination to which should be converted.
46 | /// The parameter for which the is being converted.
47 | ///
48 | /// An of type , converted using
49 | /// type converters specified on if available. If
50 | /// is then the output will be for reference
51 | /// types and the default value for value types.
52 | ///
53 | ///
54 | /// Thrown if conversion of the value fails.
55 | ///
56 | public static object? ChangeToCompatibleType(object? value, Type destinationType, MemberInfo memberInfo)
57 | {
58 | TypeConverterAttribute? attrib = null;
59 | if (memberInfo != null)
60 | {
61 | attrib = memberInfo.GetCustomAttributes(typeof(TypeConverterAttribute), true).Cast().FirstOrDefault();
62 | }
63 |
64 | return ChangeToCompatibleType(value, destinationType, attrib);
65 | }
66 |
67 | ///
68 | /// Converts an object to a type compatible with a given parameter.
69 | ///
70 | /// The object value to convert.
71 | /// The destination to which should be converted.
72 | /// A , if available, specifying the type of converter to use. is being converted.
73 | ///
74 | /// An of type , converted using
75 | /// any type converters specified in if available. If
76 | /// is then the output will be for reference
77 | /// types and the default value for value types.
78 | ///
79 | ///
80 | /// Thrown if conversion of the value fails.
81 | ///
82 | public static object? ChangeToCompatibleType(object? value, Type destinationType, TypeConverterAttribute? converterAttribute = null)
83 | {
84 | if (destinationType == null)
85 | {
86 | throw new ArgumentNullException(nameof(destinationType));
87 | }
88 |
89 | if (value == null)
90 | {
91 | return destinationType.GetTypeInfo().IsValueType ? Activator.CreateInstance(destinationType) : null;
92 | }
93 |
94 | // Try implicit conversion.
95 | if (destinationType.IsInstanceOfType(value))
96 | {
97 | return value;
98 | }
99 |
100 | TypeConverter converter;
101 |
102 | // Try to get custom type converter information.
103 | if (converterAttribute != null && !string.IsNullOrEmpty(converterAttribute.ConverterTypeName))
104 | {
105 | converter = GetTypeConverterFromName(converterAttribute.ConverterTypeName);
106 | if (converter.CanConvertFrom(value.GetType()))
107 | {
108 | return converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
109 | }
110 | }
111 |
112 | // If there's not a custom converter specified via attribute, try for a default.
113 | converter = TypeDescriptor.GetConverter(value.GetType());
114 | if (converter.CanConvertTo(destinationType))
115 | {
116 | return converter.ConvertTo(null, CultureInfo.InvariantCulture, value, destinationType);
117 | }
118 |
119 | // Try explicit opposite conversion.
120 | converter = TypeDescriptor.GetConverter(destinationType);
121 | if (converter.CanConvertFrom(value.GetType()))
122 | {
123 | return converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
124 | }
125 |
126 | // Try a TryParse method.
127 | if (value is string)
128 | {
129 | // Some types in later frameworks have string TryParse and ReadOnlySpan TryParse
130 | // so they result in an AmbiguousMatchException unless we specify.
131 | var parser = destinationType.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, CallingConventions.Standard, new Type[] { typeof(string), destinationType.MakeByRefType() }, null);
132 | if (parser != null)
133 | {
134 | var parameters = new[] { value, null };
135 | if ((bool)parser.Invoke(null, parameters))
136 | {
137 | return parameters[1];
138 | }
139 | }
140 | }
141 |
142 | throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ConfigurationResources.TypeConversionUnsupported, value.GetType(), destinationType));
143 | }
144 |
145 | ///
146 | /// Instantiates a type converter from its type name.
147 | ///
148 | ///
149 | /// The name of the of the .
150 | ///
151 | ///
152 | /// The instantiated .
153 | ///
154 | ///
155 | /// Thrown if does not correspond
156 | /// to a .
157 | ///
158 | private static TypeConverter GetTypeConverterFromName(string converterTypeName)
159 | {
160 | var converterType = Type.GetType(converterTypeName, true);
161 | return Activator.CreateInstance(converterType) is not TypeConverter converter
162 | ? throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ConfigurationResources.TypeConverterAttributeTypeNotConverter, converterTypeName))
163 | : converter;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/test/Autofac.Configuration.Test/AssertionHelpers.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | namespace Autofac.Configuration.Test;
5 |
6 | internal static class AssertionHelpers
7 | {
8 | public static void AssertRegistered(this IComponentContext context, string message = "Expected component was not registered.")
9 | {
10 | Assert.True(context.IsRegistered(), message);
11 | }
12 |
13 | public static void AssertNotRegistered(this IComponentContext context, string message = "Component was registered unexpectedly.")
14 | {
15 | Assert.False(context.IsRegistered(), message);
16 | }
17 |
18 | public static void AssertRegisteredNamed(this IComponentContext context, string service, string message = "Expected named component was not registered.")
19 | {
20 | Assert.True(context.IsRegisteredWithName(service, typeof(TService)), message);
21 | }
22 |
23 | public static void AssertNotRegisteredNamed(this IComponentContext context, string service, string message = "Named component was registered unexpectedly.")
24 | {
25 | Assert.False(context.IsRegisteredWithName(service, typeof(TService)), message);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/test/Autofac.Configuration.Test/Autofac.Configuration.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | $(NoWarn);CS1591
5 | true
6 | ../../Autofac.snk
7 | true
8 | true
9 | ../../build/Test.ruleset
10 | true
11 | false
12 | latest
13 | AllEnabledByDefault
14 | enable
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | all
51 | runtime; build; native; contentfiles; analyzers; buildtransitive
52 |
53 |
54 | all
55 | runtime; build; native; contentfiles; analyzers; buildtransitive
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | all
64 | runtime; build; native; contentfiles; analyzers; buildtransitive
65 |
66 |
67 |
68 | all
69 | runtime; build; native; contentfiles; analyzers
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/test/Autofac.Configuration.Test/Core/ComponentRegistrarFixture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Autofac Project. All rights reserved.
2 | // Licensed under the MIT License. See LICENSE in the project root for license information.
3 |
4 | using Autofac.Configuration.Core;
5 | using Autofac.Core;
6 | using Microsoft.Extensions.Configuration;
7 |
8 | namespace Autofac.Configuration.Test.Core;
9 |
10 | public class ComponentRegistrarFixture
11 | {
12 | [Fact]
13 | public void RegisterConfiguredComponents_AllowsMultipleRegistrationsOfSameType()
14 | {
15 | var builder = EmbeddedConfiguration.ConfigureContainerWithJson("ComponentRegistrar_SameTypeRegisteredMultipleTimes.json");
16 | var container = builder.Build();
17 | var collection = container.Resolve>().ToList();
18 | Assert.Equal(2, collection.Count);
19 |
20 | // Test using Any() because we aren't necessarily guaranteed the order of resolution.
21 | Assert.True(collection.Any(a => a.Input == 5.123), "The first registration (5.123) wasn't found.");
22 | Assert.True(collection.Any(a => a.Input == 10.234), "The second registration (10.234) wasn't found.");
23 | }
24 |
25 | [Fact]
26 | public void RegisterConfiguredComponents_AutoActivationEnabledOnComponent()
27 | {
28 | var builder = EmbeddedConfiguration.ConfigureContainerWithJson("ComponentRegistrar_EnableAutoActivation.json");
29 | var container = builder.Build();
30 | Assert.True(container.ComponentRegistry.TryGetRegistration(new KeyedService("a", typeof(object)), out IComponentRegistration registration), "The expected component was not registered.");
31 | Assert.True(registration.Services.Any(a => a.GetType().Name == "AutoActivateService"), "Auto activate service was not registered on the component");
32 | }
33 |
34 | [Fact]
35 | public void RegisterConfiguredComponents_AutoActivationNotEnabledOnComponent()
36 | {
37 | var builder = EmbeddedConfiguration.ConfigureContainerWithJson("ComponentRegistrar_EnableAutoActivation.json");
38 | var container = builder.Build();
39 | Assert.True(container.ComponentRegistry.TryGetRegistration(new KeyedService("b", typeof(object)), out IComponentRegistration registration), "The expected component was not registered.");
40 | Assert.False(registration.Services.Any(a => a.GetType().Name == "AutoActivateService"), "Auto activate service was registered on the component when it shouldn't be.");
41 | }
42 |
43 | [Fact]
44 | public void RegisterConfiguredComponents_ConstructorInjection()
45 | {
46 | var builder = EmbeddedConfiguration.ConfigureContainerWithXml("ComponentRegistrar_SingletonWithTwoServices.xml");
47 | var container = builder.Build();
48 | var cpt = (SimpleComponent)container.Resolve();
49 | Assert.Equal(1.234, cpt.Input);
50 | }
51 |
52 | [Fact]
53 | public void RegisterConfiguredComponents_ExternalOwnership()
54 | {
55 | var builder = EmbeddedConfiguration.ConfigureContainerWithJson("ComponentRegistrar_ExternalOwnership.json");
56 | var container = builder.Build();
57 | Assert.True(container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(SimpleComponent)), out IComponentRegistration registration), "The expected component was not registered.");
58 | Assert.Equal(InstanceOwnership.ExternallyOwned, registration.Ownership);
59 | }
60 |
61 | [Fact]
62 | public void RegisterConfiguredComponents_LifetimeScope_InstancePerDependency()
63 | {
64 | var builder = EmbeddedConfiguration.ConfigureContainerWithJson("ComponentRegistrar_InstancePerDependency.json");
65 | var container = builder.Build();
66 | Assert.NotSame(container.Resolve(), container.Resolve());
67 | }
68 |
69 | [Fact]
70 | public void RegisterConfiguredComponents_LifetimeScope_Singleton()
71 | {
72 | var builder = EmbeddedConfiguration.ConfigureContainerWithXml("ComponentRegistrar_SingletonWithTwoServices.xml");
73 | var container = builder.Build();
74 | Assert.Same(container.Resolve(), container.Resolve());
75 | }
76 |
77 | [Fact]
78 | public void RegisterConfiguredComponents_PropertyInjectionEnabledOnComponent()
79 | {
80 | var builder = EmbeddedConfiguration.ConfigureContainerWithJson("ComponentRegistrar_EnablePropertyInjection.json");
81 | builder.RegisterType().As();
82 | builder.RegisterInstance("hello").As();
83 | var container = builder.Build();
84 | var e = container.Resolve();
85 | Assert.NotNull(e.Component);
86 |
87 | // Issue #2 - Ensure properties in base classes can be set by config.
88 | Assert.Equal("hello", e.Message);
89 | }
90 |
91 | [Fact]
92 | public void RegisterConfiguredComponents_NullConfiguration()
93 | {
94 | var registrar = new ComponentRegistrar();
95 | var builder = new ContainerBuilder();
96 | Assert.Throws(() => registrar.RegisterConfiguredComponents(builder, null));
97 | }
98 |
99 | [Fact]
100 | public void RegisterConfiguredComponents_NullContainerBuilder()
101 | {
102 | var registrar = new ComponentRegistrar();
103 | var config = new ConfigurationBuilder().Build();
104 | Assert.Throws(() => registrar.RegisterConfiguredComponents(null, config));
105 | }
106 |
107 | [Fact]
108 | public void RegisterConfiguredComponents_PropertyInjectionWithProvidedValues()
109 | {
110 | var builder = EmbeddedConfiguration.ConfigureContainerWithXml("ComponentRegistrar_SingletonWithTwoServices.xml");
111 | var container = builder.Build();
112 | var cpt = (SimpleComponent)container.Resolve();
113 | Assert.True(cpt.ABool, "The Boolean property value was not properly parsed/converted.");
114 |
115 | // Issue #2 - Ensure properties in base classes can be set by config.
116 | Assert.Equal("hello", cpt.Message);
117 | }
118 |
119 | [Fact]
120 | public void RegisterConfiguredComponents_RegistersMetadata()
121 | {
122 | var builder = EmbeddedConfiguration.ConfigureContainerWithJson("ComponentRegistrar_ComponentWithMetadata.json");
123 | var container = builder.Build();
124 | Assert.True(container.ComponentRegistry.TryGetRegistration(new KeyedService("a", typeof(object)), out IComponentRegistration registration), "The expected service wasn't registered.");
125 | Assert.Equal(42.42, (double)registration.Metadata["answer"]);
126 | }
127 |
128 | [Fact]
129 | public void RegisterConfiguredComponents_SingleComponentWithTwoServices()
130 | {
131 | var builder = EmbeddedConfiguration.ConfigureContainerWithXml("ComponentRegistrar_SingletonWithTwoServices.xml");
132 | var container = builder.Build();
133 | container.AssertRegistered("The ITestComponent wasn't registered.");
134 | container.AssertRegistered