官方文檔: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>();
這將迫使引用的程序集被加載到應用程序域立即使其可用於模塊掃描。