官方文档:http://docs.autofac.org/en/latest/register/scanning.html
Autofac 组件扫描
在程序集中Autofac 可以使用约定来找到并注册组件,你可以扫描并注册自定义类型或者为Autofac 模块专门进行扫描。
1、扫描类型
在其他方面,被称为约定驱动的注册或扫描,Autofac可以根据用户指定的规则从一个程序集中注册一组类型:
var dataAccess = Assembly.GetExecutingAssembly(); builder.RegisterAssemblyTypes(dataAccess) .Where(t => t.Name.EndsWith("Repository")) .AsImplementedInterfaces();
每个RegisterAssemblyTypes()
调用将适用一组规则,如果有多种不同的组件注册,一次或多次调用RegisterAssemblyTypes()
是非常有必要的。
-
过滤类型(Filtering Types)
RegisterAssemblyTypes()接受一个或多个程序集的参数数组。默认情况下,程序集中的所有的公共的,具体类将被注册。你可以过滤一组注册的类型,通过使用linq表达式。
过滤注册类型,使用Where()语法过滤:
builder.RegisterAssemblyTypes(asm) .Where(t => t.Name.EndsWith("Repository"));
从扫描排除类型,可以使用
Except():
builder.RegisterAssemblyTypes(asm) .Except<MyUnwantedType>();
Except()
允许你自定义特定的排除类型来注册
builder.RegisterAssemblyTypes(asm) .Except<MyCustomisedType>(ct => ct.As<ISpecial>().SingleInstance());
可以使用多个过滤器,在这种情况下,他们通过AND来追加。
-
指定服务(Specifying Services)
对于RegisterAssemblyTypes()注册语法是单个类型注册语法的超级集合,所以像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(); |
2、扫描模块
模块扫描使用RegisterAssemblyModules()注册方法执行,它的名字是什么,就执行哪个。它通过Autofac 模块提供的程序集扫描,创建模块实例,然后使用当前container builder 注册他们。
例如,两个简单的模块类属于同一程序集并且每个注册一个组件:
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()使用object类型参数重载,就像泛型类型参数重载,但允许你指定类型,它可能在运行时确定。在下面的例子中,仅一个模块被注册,因为扫描被限制:
var assembly = typeof(AComponent).Assembly; var builder = new ContainerBuilder(); // 只注册AModule 不会注册 BModule builder.RegisterAssemblyModules(typeof(AModule), assembly);
3、IIS托管Web应用程序
当使用IIS应用程序集扫描,配置程序集的位置可能会遇到一点小麻烦。
当在IIS托管应用程序,当第一次启动应用程序时,所有程序集被加载到AppDomain中,但是当AppDomain被IIS回收时,程序集仅按需加载。
为了避免这个问题,使用System.Web.Compilation.BuildManager中的GetReferencedAssemblies()方法,会得到一个引用程序集列表。
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();
这将迫使引用的程序集被加载到应用程序域立即使其可用于模块扫描。