项目
版本

Autofac 组装扫描

Autofac 可以使用约定来查找和注册组件。您可以扫描并注册单个类型,也可以专门针对 Autofac 模块 进行扫描。

类型扫描

也称为约定驱动注册或扫描,Autofac 可根据用户指定的规则从一个程序集中注册一组类型:

var dataAccess = Assembly.GetExecutingAssembly();

builder.RegisterAssemblyTypes(dataAccess)
       .Where(t => t.Name.EndsWith("Repository"))
       .AsImplementedInterfaces();

每次调用 RegisterAssemblyTypes() 都只会应用一套规则 - 如果有多个不同的组件集合需要注册,则需要多次调用 RegisterAssemblyTypes()

Autofac 还支持使用 RegisterAssemblyOpenGenericTypes() 进行泛型开放类型的程序集扫描。它使用与 RegisterAssemblyTypes() 类似的通用语义:

var dataAccess = Assembly.GetExecutingAssembly();

builder.RegisterAssemblyOpenGenericTypes(dataAccess)
       .Where(t => t.Name.StartsWith("MessageHandler"))
       .AsImplementedInterfaces();

过滤类型

RegisterAssemblyTypes()RegisterAssemblyOpenGenericTypes() 分别接受一个或多个程序集的参数数组。默认情况下,将注册程序集中所有具体的类 ,包括内部和私嵌套类。您可以使用提供的 LINQ 样式的谓词来过滤要注册的类型集。

在 4.8.0 中添加了 PublicOnly() 扩展方法,使数据封装更加方便。如果您只想注册公开类,请使用 PublicOnly()

builder.RegisterAssemblyTypes(asm)
       .PublicOnly();

要应用自定义过滤器到注册的类型,使用 Where() 谓词:

builder.RegisterAssemblyTypes(asm)
       .Where(t => t.Name.EndsWith("Repository"));

要排除类型进行扫描,请使用 Except() 谓词:

builder.RegisterAssemblyTypes(asm)
       .Except<MyUnwantedType>();

Except() 谓词还允许您为特定排除类型自定义注册:

builder.RegisterAssemblyTypes(asm)
       .Except<MyCustomizedType>(ct =>
          ct.As<ISpecial>().SingleInstance());

可以使用多个过滤器,此时它们将按逻辑与应用。

builder.RegisterAssemblyTypes(asm)
       .PublicOnly()
       .Where(t => t.Name.EndsWith("Repository"))
       .Except<MyUnwantedRepository>();

指定服务

RegisterAssemblyTypes()RegisterAssemblyOpenGenericTypes() 的注册语法是单个类型注册语法的子集,因此像 As() 这样的方法对程序集也适用:

builder.RegisterAssemblyTypes(asm)
       .Where(t => t.Name.EndsWith("Repository"))
       .As<IRepository>();

As()Named() 方法的额外重载接受决定类型将提供哪些服务的 lambda 表达式:

builder.RegisterAssemblyTypes(asm)
       .As(t => t.GetInterfaces()[0]);

与常规组件注册一样,多次调用 As() 将组合在一起。

为了更容易建立常见的约定,已添加了一些额外的注册方法:

方法 描述 示例
AsImplementedInterfaces() 将类型注册为提供其公开接口(排除 IDisposable)作为服务。 builder.RegisterAssemblyTypes(asm).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces();
AsClosedTypesOf(open) 注册可以赋值给封闭的泛型类型的类型。 builder.RegisterAssemblyTypes(asm).AsClosedTypesOf(typeof(IRepository<>));
AsSelf() 默认:将类型注册为自身 - 当与其他服务规范一起覆盖默认行为时很有用。 builder.RegisterAssemblyTypes(asm).AsImplementedInterfaces().AsSelf();

模块扫描

模块扫描由 RegisterAssemblyModules() 注册方法执行,顾名思义,它会扫描提供的程序集,创建模块实例,然后将它们注册到当前容器构建器。

例如,如果下面两个简单的模块类位于同一个程序集中,并且每个都注册一个组件:

public class AModule : Module
{
  protected override void Load(ContainerBuilder builder)
  {
    builder.Register(c => new AComponent()).As<AComponent>();
  }
}

public class BModule : Module
{
  protected override void Load(ContainerBuilder builder)
  {
    builder.Register(c => new BComponent()).As<BComponent>();
  }
}

不接受类型参数的 RegisterAssemblyModules() 重载将注册程序集中实现 IModule 的所有类。在下面的例子中,两个模块都会被注册

var assembly = typeof(AComponent).Assembly;
var builder = new ContainerBuilder();

// 注册两个模块
builder.RegisterAssemblyModules(assembly);

带泛型类型参数的 RegisterAssemblyModules() 重载允许您指定模块必须继承的基类型。在下面的例子中,只注册了一个模块,因为扫描受到了限制:

var assembly = typeof(AComponent).Assembly;
var builder = new ContainerBuilder();

// 注册 AModule 但不注册 BModule
builder.RegisterAssemblyModules<AModule>(assembly);

带类型对象参数的 RegisterAssemblyModules() 重载工作起来像泛型类型参数重载,但它允许您指定可能在运行时确定的类型。在下面的例子中,只注册了一个模块,因为扫描受到了限制:

var assembly = typeof(AComponent).Assembly;
var builder = new ContainerBuilder();

// 注册 AModule 但不注册 BModule
builder.RegisterAssemblyModules(typeof(AModule), assembly);

IIS 托管的 Web 应用程序

在使用 IIS 应用程序进行程序集扫描时,根据您的做法可能会遇到一些问题( 这是我们的常见问题之一 )。

在 IIS 中托管应用程序时,应用程序首次启动时所有程序集都会加载到 AppDomain 中,但当 IIS 重新启动 AppDomain 时,这些程序集将仅按需加载

要解决此问题,请使用 GetReferencedAssemblies() 方法从 System.Web.Compilation.BuildManager 获取引用的程序集列表:

var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();

这将强制引用的程序集立即加载到 AppDomain 中,使其可用于模块扫描。

在本文档中