Autofac 使用 JSON 或 XML 配置
大多数 IoC 容器都提供了程序接口以及基于 JSON 或 XML 的配置支持,Autofac 也不例外。
Autofac 通过 ContainerBuilder
类鼓励使用程序化配置。通过程序化接口是容器设计的核心。当在编译时无法选择或配置具体类时,推荐使用 JSON 或 XML。
深入研究 JSON 或 XML 配置之前,请务必阅读 模块 部分,它解释了 JSON 或 XML 组件注册无法处理的复杂场景。JSON 或 XML 配置并不是程序化配置功能对功能的替代,因此复杂的场景可能需要结合 JSON 和模块一起使用。
使用 Microsoft 配置 (4.0+)
注意 Microsoft 配置适用于 Autofac.Configuration 4.0 及更高版本。它不适用于该包的早期版本。
随着 Microsoft.Extensions.Configuration 的发布,以及 Autofac.Configuration 4.0.0,Autofac 利用了过去受限于应用程序配置文件(如 app.config
或 web.config
)时无法获得的更灵活的配置模型。如果您之前使用过这些配置文件,您需要将配置迁移到新格式,并更新与应用程序容器设置配置的方式。
快速入门
设置应用程序配置的基本步骤如下:
- 设置可以在
Microsoft.Extensions.Configuration
中读取的 JSON 或 XML 文件。- JSON 配置使用
Microsoft.Extensions.Configuration.Json
- XML 配置使用
Microsoft.Extensions.Configuration.Xml
- JSON 配置使用
- 使用
Microsoft.Extensions.Configuration.ConfigurationBuilder
构建配置。 - 创建一个
Autofac.Configuration.ConfigurationModule
,并将构建好的Microsoft.Extensions.Configuration.IConfiguration
传递给它。 - 将
Autofac.Configuration.ConfigurationModule
注册到您的容器中。
包含一些简单注册的配置文件看起来像这样:
{
"defaultAssembly": "Autofac.Example.Calculator",
"components": [
{
"type": "Autofac.Example.Calculator.Addition.Add, Autofac.Example.Calculator.Addition",
"services": [
{
"type": "Autofac.Example.Calculator.Api.IOperation"
}
],
"injectProperties": true
},
{
"type": "Autofac.Example.Calculator.Division.Divide, Autofac.Example.Calculator.Division",
"services": [
{
"type": "Autofac.Example.Calculator.Api.IOperation"
}
],
"parameters": {
"places": 4
}
}
]
}
JSON 更干净、易读,但如果您更喜欢 XML,同样的配置会看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<autofac defaultAssembly="Autofac.Example.Calculator">
<components name="0">
<type>Autofac.Example.Calculator.Addition.Add, Autofac.Example.Calculator.Addition</type>
<services name="0" type="Autofac.Example.Calculator.Api.IOperation" />
<injectProperties>true</injectProperties>
</components>
<components name="1">
<type>Autofac.Example.Calculator.Division.Divide, Autofac.Example.Calculator.Division</type>
<services name="0" type="Autofac.Example.Calculator.Api.IOperation" />
<injectProperties>true</injectProperties>
<parameters>
<places>4</places>
</parameters>
</components>
</autofac>
请注意 XML 中组件和服务的序号命名——这是由于 Microsoft.Extensions.Configuration
处理有序集合(数组)的方式造成的。
按照以下方式将配置构建并注册到 Autofac ContainerBuilder
:
// 将配置添加到 ConfigurationBuilder。
var config = new ConfigurationBuilder();
// config.AddJsonFile 来自 Microsoft.Extensions.Configuration.Json
// config.AddXmlFile 来自 Microsoft.Extensions.Configuration.Xml
config.AddJsonFile("autofac.json");
// 将 ConfigurationModule 注册到 Autofac。
var module = new ConfigurationModule(config.Build());
var builder = new ContainerBuilder();
builder.RegisterModule(module);
默认程序集
您可以在配置中指定一个“默认程序集”选项,以帮助您以更短的形式写类型。如果在类型或接口引用中未指定完整的程序集限定类型名称,将假设其位于默认程序集中。
{
"defaultAssembly": "Autofac.Example.Calculator"
}
组件
组件是最常见的注册项。您可以为每个组件指定从生命周期范围到参数的各种内容。
组件在配置中的顶级 components
元素中添加。其中包含要注册的所有组件。
这个示例显示了一个组件,它包含了所有选项,只是为了说明语法。在实际组件注册中,您不会在每个注册中使用所有这些选项。
{
"components": [
{
"type": "Autofac.Example.Calculator.Addition.Add, Autofac.Example.Calculator.Addition",
"services": [
{
"type": "Autofac.Example.Calculator.Api.IOperation"
},
{
"type": "Autofac.Example.Calculator.Api.IAddOperation",
"key": "add"
}
],
"autoActivate": true,
"injectProperties": true,
"instanceScope": "per-dependency",
"metadata": [
{
"key": "answer",
"value": 42,
"type": "System.Int32, mscorlib"
}
],
"ownership": "external",
"parameters": {
"places": 4
},
"properties": {
"DictionaryProp": {
"key": "value"
},
"ListProp": [1, 2, 3, 4, 5]
}
}
]
}
元素名称 | 描述 | 有效值 |
---|---|---|
type |
唯一必需的。组件的 concrete 类(如果在非默认程序集中的话,需要指定完整的程序集限定类型名称)。 | 可以通过反射创建的任何 .NET 类型名称。 |
services |
组件公开的服务的数组。每个服务必须有 type ,可选地指定 key 。 |
可以通过反射创建的任何 .NET 类型名称。 |
autoActivate |
一个布尔值,指示组件是否应该 自动激活 。 | true , false |
injectProperties |
一个布尔值,指示是否应 为组件启用属性注入 。 | true , false |
instanceScope |
组件的 实例范围 。 | singleinstance , perlifetimescope , perdependency , perrequest |
metadata |
一个 元数据值数组 ,用于关联组件。每个条目指定 name 、type 和 value 。 |
任何 元数据值 。 |
ownership |
允许您控制 组件的生命周期范围是否负责释放组件,还是由您的代码负责 。 | lifetimescope , external |
parameters |
一个名值字典,其中每个元素的名称是构造函数参数的名称,值是要注入的值。 | 组件类型的构造函数中的任意参数。 |
properties |
一个名值字典,其中每个元素的名称是属性的名称,值是要注入的值。 | 组件类型上的任何可设置属性。 |
注意,parameters
和 properties
都支持字典和枚举值。您可以在 JSON 结构的示例中看到如何指定这些内容。
模块
在使用 Autofac 时,可以将模块与组件一起使用配置来注册。模块作为配置中的顶级 modules
元素内的一个数组添加。
以下示例显示了一个具有所有选项的模块,只是为了说明语法。实际上,在每个模块注册时,您不会使用所有这些选项。
{
"modules": [
{
"type": "Autofac.Example.Calculator.OperationModule, Autofac.Example.Calculator",
"parameters": {
"places": 4
},
"properties": {
"DictionaryProp": {
"key": "value"
},
"ListProp": [1, 2, 3, 4, 5]
}
}
]
}
元素名称 | 描述 | 有效值 |
---|---|---|
type |
必须填写。模块的具体类(如果在默认以外的其他程序集中,需要提供完整的类型名)。 | 任何从 Autofac.Module 派生且可以通过反射创建的.NET 类型。 |
parameters |
名值字典,其中每个元素的名称是构造函数参数的名称,值是要注入的值。 | 模块类型构造函数中的任何参数。 |
properties |
名值字典,其中每个元素的名称是属性的名称,值是要注入的值。 | 模块类型的任何可设置属性。 |
请注意,parameters
和 properties
都支持字典和枚举值。上面的 JSON 结构中已经展示了如何指定这些。
如果愿意,您可以根据不同的参数/属性集多次注册同一个模块。
类型名称
在所有情况下,只要看到类型名称(组件类型、服务类型、模块类型),预期它将是标准的、完整类型名(MSDN 文档),通常可以传递给 Type.GetType(string typename)
。如果类型在 defaultAssembly
中,您可以省略 assembly 名称,但无论如何添加它都没有坏处。
完整的类型名包含命名空间、逗号和 assembly 名称,例如 Autofac.Example.Calculator.OperationModule, Autofac.Example.Calculator
。在这种情况下,Autofac.Example.Calculator.OperationModule
是类型,它位于 Autofac.Example.Calculator
assembly 中。
泛型稍微复杂一些。配置不支持开放泛型,因此也需要指定每个泛型参数的完全限定名称。
例如,假设在 ConfigWithGenericsDemo
assembly 中有一个泛型接口 IRepository<T>
,并且有一个名为 StringRepository
的类实现了 IRepository<string>
。要在配置中注册它,如下所示:
{
"components": [
{
"type": "ConfigWithGenericsDemo.StringRepository, ConfigWithGenericsDemo",
"services": [
{
"type": "ConfigWithGenericsDemo.IRepository`1[[System.String, mscorlib]], ConfigWithGenericsDemo"
}
]
}
]
}
如果您难以确定类型名称,可以在代码中使用类似的方法:
// 将类型名称写入调试输出窗口,并从中复制粘贴到配置中。
System.Diagnostics.Debug.WriteLine(typeof(IRepository<string>).AssemblyQualifiedName);
与旧版配置的差异
从基于 app.config
的旧版(版本 4.0 之前)配置迁移到新格式时,需要注意以下几点:
- 没有 ConfigurationSettingsReader。
Microsoft.Extensions.Configuration
完全取代了旧的 XML 格式配置。旧版配置文档不适用于 4.0 及更高版本的配置包。 - 多个配置文件处理方式不同。 旧版配置有一个
files
元素,可以自动同时加载几个文件进行配置。现在使用Microsoft.Extensions.Configuration.ConfigurationBuilder
来实现这一点。 - 自动激活已支持。 现在可以指定 自动激活组件,这是以前配置中不可用的功能。
- XML 使用子元素而非属性。 这有助于保持 XML 和 JSON 解析器的兼容性,以便正确组合 XML 和 JSON 配置源。
- 使用 XML 需要为组件和服务命名并使用数字。
Microsoft.Extensions.Configuration
要求每个配置项都有名称和值。它支持有序集合(数组)的方式是为集合中的无名元素自动分配数字名称(如 "0"、"1" 等)。如果您不使用 JSON,需要留意这个要求,否则可能无法得到预期结果。 - 支持按请求生命周期范围。 以前无法配置元素以具有 每个请求生命周期范围。现在可以。
- 名称/值中的破折号已移除。 XML 元素名称以前包含破折号,如
inject-properties
,现在为了与 JSON 配置格式兼容,它们使用驼峰命名法,如injectProperties
。 - 服务在子元素中指定。 旧版配置允许直接在组件顶部声明服务。新系统要求所有服务都在
services
集合中。
更多提示
新的 Microsoft.Extensions.Configuration
机制提供了很多灵活性。您可以利用以下功能:
- 环境变量支持。 可以使用
Microsoft.Extensions.Configuration.EnvironmentVariables
来根据环境进行配置更改。快速调试、修补或修复代码而无需更改代码的一个方法是根据环境切换 Autofac 注册。 - 易于配置合并。
ConfigurationBuilder
允许您从多个来源创建配置并合并它们。如果有很多配置,考虑扫描您的配置文件并动态构建配置,而不是硬编码路径。 - 自定义配置源。 您可以实现自己的
Microsoft.Extensions.Configuration.ConfigurationProvider
,它背后不仅仅依赖于文件。如果您想集中配置,可以考虑使用数据库或 REST API 支持的配置源。
使用应用程序配置(旧版预 4.0)
注意 下面描述的旧版应用程序配置适用于 3.x 版本及更早的 Autofac.Configuration。它不适用于 4.0 及更高版本的包。
在 Microsoft.Extensions.Configuration
和更新的配置模型发布之前,Autofac 与标准 .NET 应用程序配置文件(app.config
/ web.config
)集成。在 3.x 版本的 Autofac.Configuration 包中,这是配置的主要方式。
设置
使用旧版配置机制,您需要在配置文件的顶部附近声明一个节处理器:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
</configSections>
然后,提供一个描述组件的节:
<autofac defaultAssembly="Autofac.Example.Calculator.Api">
<components>
<component
type="Autofac.Example.Calculator.Addition.Add, Autofac.Example.Calculator.Addition"
service="Autofac.Example.Calculator.Api.IOperation" />
<component
type="Autofac.Example.Calculator.Division.Divide, Autofac.Example.Calculator.Division"
service="Autofac.Example.Calculator.Api.IOperation" >
<parameters>
<parameter name="places" value="4" />
</parameters>
</component>
</components>
</autofac>
defaultAssembly
属性是可选的,允许使用命名空间限定而非完全限定的类型名称,这可以节省一些混乱和打字,特别是如果您使用一个配置文件对应一个程序集(参见下面的附加配置文件)。
组件
组件是最常见的注册项。您可以为每个组件指定许多内容,从生命周期范围到参数。
组件属性
以下属性可用于 component
元素(默认值与程序化 API 相同):
属性名称 | 描述 | 有效值 |
---|---|---|
type |
必需属性。组件的实现类(如果在非默认命名空间的程序集中,则使用完全限定名)。 | 可以通过反射创建的任何 .NET 类型名称。 |
service |
组件公开的服务。对于多个服务,请使用嵌套的 services 元素。 |
类似于 type 。 |
instance-scope |
实例作用域 - 参见 实例作用域。 | per-dependency 、single-instance 或 per-lifetime-scope |
instance-ownership |
容器对实例的所有权 - 参见 InstanceOwnership 枚举。 |
lifetime-scope 或 external |
name |
组件的字符串名称。 | 任何非空字符串值。 |
inject-properties |
启用组件的属性(设置器)注入。 | yes 、no |
组件子元素
元素 | 描述 |
---|---|
services |
包含组件公开服务类型的列表(参见 service 属性)的 service 元素。 |
parameters |
显式构造参数列表,用于设置实例(如上所示的示例)。 |
properties |
显式属性值列表(与 parameters 语法相同)。 |
metadata |
包含 name 、value 和 type 属性的 item 节点列表。 |
XML 配置语法中缺少了一些可通过编程 API 提供的功能,例如注册泛型。在这种情况下,建议使用模块。
模块
使用组件精细配置容器可能会变得繁琐。Autofac 支持将组件封装到 模块 中,以封装实现并提供灵活的配置。
通过类型注册模块:
<modules>
<module type="MyModule" />
与上述组件类似,您可以在模块注册中添加嵌套的 parameters
和 properties
。
额外配置文件
您可以使用以下方式包含其他配置文件:
<files>
<file name="Controllers.config" section="controllers" />
配置容器
首先,您的项目必须引用 Autofac.Configuration.dll。
使用 ConfigurationSettingsReader
初始化容器配置,其中包含您给 XML 配置节的名称:
var builder = new ContainerBuilder();
builder.RegisterModule(new ConfigurationSettingsReader("mycomponents"));
// 注册其他组件并调用Build()创建容器。
容器设置读取器会覆盖已注册的默认组件;您可以编写应用程序,使其在默认情况下运行良好,然后只针对特定部署重写必要的组件注册。
多个文件或节
在同一个容器中可以使用多个设置读取器,以读取不同的节,甚至如果提供了文件名给 ConfigurationSettingsReader
构造函数,还可以读取不同的配置文件。