Autofac
可以使用约定来查找和注册程序集中的组件。 您可以扫描并注册各种类型,也可以专门扫描Autofac模块。
扫描类型
否则称为惯例驱动的注册或扫描,Autofac可以根据用户指定的规则从程序集中注册一组类型:
var dataAccess = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(dataAccess)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces();
每个RegisterAssemblyTypes()
调用将仅应用一组规则 - 如果要注册多个不同组的组件,则需要多次调用RegisterAssemblyTypes()
。
过滤类型
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。
指定服务
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()
的调用被加在一起。
增加了一些额外的注册方法,以便更容易地建立通用约定:
Method | Description | Example |
---|---|---|
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()
注册方法来完成的,而注册方法正是其名字所暗示的。 它扫描所提供的Autofac模块的程序集,创建模块的实例,然后将其注册到当前的容器生成器。
例如,假设下面的两个简单模块类存在同一个程序集中,并且每个注册一个组件:
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();
//注册模块但不包含BModule
builder.RegisterAssemblyModules<AModule>(assembly);
使用Type对象参数的RegisterAssemblyModules()
的重载与通用类型参数重载类似,但允许您指定可能在运行时确定的类型。 在下面的例子中,只有一个模块被注册,因为扫描受到限制:
var assembly = typeof(AComponent).Assembly;
var builder = new ContainerBuilder();
// 注册模块但不包含BModule
builder.RegisterAssemblyModules(typeof(AModule), assembly);
IIS托管的Web应用程序
在IIS应用程序中使用程序集扫描时,根据程序集位置的不同,可能会遇到一些麻烦。 (这是我们的常见问题之一)
在IIS中托管应用程序时,应用程序首次启动时,所有程序集都加载到AppDomain
中,但当AppDomain
被IIS回收时,程序集仅在需要时加载。
为避免此问题,请使用System.Web.Compilation.BuildManager
上的GetReferencedAssemblies()
方法来获取引用程序集的列表:
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();
这将强制引用的程序集立即加载到AppDomain中,使其可用于模块扫描.