项目
版本

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.configweb.config)时无法获得的更灵活的配置模型。如果您之前使用过这些配置文件,您需要将配置迁移到新格式,并更新与应用程序容器设置配置的方式。

快速入门

设置应用程序配置的基本步骤如下:

  1. 设置可以在 Microsoft.Extensions.Configuration 中读取的 JSON 或 XML 文件。
    • JSON 配置使用 Microsoft.Extensions.Configuration.Json
    • XML 配置使用 Microsoft.Extensions.Configuration.Xml
  2. 使用 Microsoft.Extensions.Configuration.ConfigurationBuilder 构建配置。
  3. 创建一个 Autofac.Configuration.ConfigurationModule,并将构建好的 Microsoft.Extensions.Configuration.IConfiguration 传递给它。
  4. 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 一个 元数据值数组 ,用于关联组件。每个条目指定 nametypevalue 任何 元数据值
ownership 允许您控制 组件的生命周期范围是否负责释放组件,还是由您的代码负责 lifetimescope, external
parameters 一个名值字典,其中每个元素的名称是构造函数参数的名称,值是要注入的值。 组件类型的构造函数中的任意参数。
properties 一个名值字典,其中每个元素的名称是属性的名称,值是要注入的值。 组件类型上的任何可设置属性。

注意,parametersproperties 都支持字典和枚举值。您可以在 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 名值字典,其中每个元素的名称是属性的名称,值是要注入的值。 模块类型的任何可设置属性。

请注意,parametersproperties 都支持字典和枚举值。上面的 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-dependencysingle-instanceper-lifetime-scope
instance-ownership 容器对实例的所有权 - 参见 InstanceOwnership 枚举。 lifetime-scopeexternal
name 组件的字符串名称。 任何非空字符串值。
inject-properties 启用组件的属性(设置器)注入。 yesno

组件子元素

元素 描述
services 包含组件公开服务类型的列表(参见 service 属性)的 service 元素。
parameters 显式构造参数列表,用于设置实例(如上所示的示例)。
properties 显式属性值列表(与 parameters 语法相同)。
metadata 包含 namevaluetype 属性的 item 节点列表。

XML 配置语法中缺少了一些可通过编程 API 提供的功能,例如注册泛型。在这种情况下,建议使用模块。

模块

使用组件精细配置容器可能会变得繁琐。Autofac 支持将组件封装到 模块 中,以封装实现并提供灵活的配置。

通过类型注册模块:

    <modules>
        <module type="MyModule" />

与上述组件类似,您可以在模块注册中添加嵌套的 parametersproperties

额外配置文件

您可以使用以下方式包含其他配置文件:

    <files>
        <file name="Controllers.config" section="controllers" />

配置容器

首先,您的项目必须引用 Autofac.Configuration.dll

使用 ConfigurationSettingsReader 初始化容器配置,其中包含您给 XML 配置节的名称:

var builder = new ContainerBuilder();
builder.RegisterModule(new ConfigurationSettingsReader("mycomponents"));
// 注册其他组件并调用Build()创建容器。

容器设置读取器会覆盖已注册的默认组件;您可以编写应用程序,使其在默认情况下运行良好,然后只针对特定部署重写必要的组件注册。

多个文件或节

在同一个容器中可以使用多个设置读取器,以读取不同的节,甚至如果提供了文件名给 ConfigurationSettingsReader 构造函数,还可以读取不同的配置文件。

在本文档中