Autofac提供了在構建容器時通知群組件或自動啟用組件的功能。
有三種自動啟用機制可用: - 可啟動組件 - 自動啟用組件 - 容器構建回調
在所有情況下,當容器建成時,組件將被啟用。 可開機組件
一個可開機組件是容器在最初構建時被容器啟用的組件,並且有一個特定的方法被調用來引導組件上的一個動作。
關鍵是要實現Autofac.IStartable介面。在構建容器時,組件將被啟用,並調用IStartable.Start()方法。
這隻會發生一次,對於每個組件的單個執行個體,首次構建容器。手動解析可啟動組件不會導致調用Start()方法。不建議可啟動組件實現其他服務,或者註冊為SingleInstance()以外的任何其他服務。
每次被啟用時需要像Start()方法那樣的組件應該使用像OnActivated這樣的生存事件。
要建立可啟動組件,請實現Autofac.IStartable:
public class StartupMessageWriter : IStartable{ public void Start() { Console.WriteLine("App is starting up!"); }}
然後註冊你的組件,並確保將其指定為IStartable,否則該操作將不會被調用:
var builder = new ContainerBuilder();builder .RegisterType<StartupMessageWriter>() .As<IStartable>() .SingleInstance();
在構建容器時,類型將被啟用,並調用IStartable.Start()方法。 在這個例子中,一條訊息將被寫入控制台。
已知問題:雖然IStartable組件將以依賴性順序解析,但Start()方法實際上可能不會以依賴性順序調用。 您可以使用與SingleInstance註冊相結合的容器構建回調來解決此問題。 見下文。 自動啟用的組件
一個自動啟用的組件是一個組件,只需要在構建容器時啟用一次。 這是一種“暖開機”的行為方式,其中組件的任何方法都不被調用,也不需要實現介面 - 組件的單個執行個體將被解析,而不涉及它所持有的執行個體。
要註冊自動啟用的組件,請使用AutoActivate()註冊擴充。
var builder = new ContainerBuilder();builder .RegisterType<TypeRequiringWarmStart>() .AsSelf() .AutoActivate();
注意:如果您在註冊AutoActivate()組件時忽略AsSelf()或As<T>()服務註冊調用,則組件只會被註冊為自動啟用,容器構建後並不一定會在解析“自身” 。 容器構建回調
您可以通過註冊構建回調來註冊任何在容器構建時發生的任意動作。 構建回調是一個Action<IContainer>,並將從ContainerBuilder.Build返回該容器之前擷取構建的容器。 構建回調按照它們註冊的順序執行:
var builder = new ContainerBuilder();builder .RegisterBuildCallback(c => c.Resolve<DbContext>());/回調將在容器產生之後但返回之前運行var container = builder.Build();
您可以使用構建回調作為在容器構建中自動啟動/預熱對象的另一種方法。 通過將它們與生命週期事件OnActivated和SingleInstance註冊結合使用來實現這一點。 這可以解決IStartable實現以依賴順序解析的已知問題,但Start()方法不一定按依賴順序調用。
單元測試形式中的一個冗長/人為的例子:
public class TestClass{ // 建立一個依賴鏈 像: // ==> 2 ==+ // 4 =+ ==> 1 // ==> 3 ==+ // 4需要2和3 // 2需要1 // 3需要1 // 依賴應該按順序啟動 // 1, 2, 3, 4 // 或者 // 1, 3, 2, 4 private class Dependency1 { public Dependency1(ITestOutputHelper output) { output.WriteLine("Dependency1.ctor"); } } private class Dependency2 { private ITestOutputHelper output; public Dependency2(ITestOutputHelper output, Dependency1 dependency) { this.output = output; output.WriteLine("Dependency2.ctor"); } public void Initialize() { this.output.WriteLine("Dependency2.Initialize"); } } private class Dependency3 { private ITestOutputHelper output; public Dependency3(ITestOutputHelper output, Dependency1 dependency) { this.output = output; output.WriteLine("Dependency3.ctor"); } public void Initialize() { this.output.WriteLine("Dependency3.Initialize"); } } private class Dependency4 { private ITestOutputHelper output; public Dependency4(ITestOutputHelper output, Dependency2 dependency2, Dependency3 dependency3) { this.output = output; output.WriteLine("Dependency4.ctor"); } public void Initialize() { this.output.WriteLine("Dependency4.Initialize"); } } //Xunit把這個傳遞給測試類別的ctor,所以我們可以捕獲控制台輸出。 private ITestOutputHelper _output; public TestClass(ITestOutputHelper output) { this._output = output; } [Fact] public void OnActivatedDependencyChain() { var builder = new ContainerBuilder(); builder.RegisterInstance(this._output).As<ITestOutputHelper>(); builder.RegisterType<Dependency1>().SingleInstance(); //OnActivated取代了IStartable的需要。 當一個執行個體被啟用/建立時,它將按照指定的方式運行Initialize方法。 使用SingleInstance意味著只發生一次。 builder.RegisterType<Dependency2>().SingleInstance().OnActivated(args => args.Instance.Initialize()); builder.RegisterType<Dependency3>().SingleInstance().OnActivated(args => args.Instance.Initialize()); builder.RegisterType<Dependency4>().SingleInstance().OnActivated(args => args.Instance.Initialize()); //注意這些不是依賴性順序 builder.RegisterBuildCallback(c => c.Resolve<Dependency4>()); builder.RegisterBuildCallback(c => c.Resolve<Dependency2>()); builder.RegisterBuildCallback(c => c.Resolve<Dependency1>()); builder.RegisterBuildCallback(c => c.Resolve<Dependency3>()); // 這將運行構建回調。 var container = builder.Build(); //這些沒有任何作用。 OnActivated不會再被調用,因為它們是SingleInstance。 container.Resolve<Dependency1>(); container.Resolve<Dependency2>(); container.Resolve<Dependency3>(); container.Resolve<Dependency4>(); }}
這個樣本單元測試會產生這個輸出:
Dependency1.ctorDependency2.ctorDependency3.ctorDependency4.ctorDependency2.InitializeDependency3.InitializeDependency4.Initialize
你會從輸出中看到,以依賴順序執行的回呼函數和OnActivated方法。 如果你必須有啟用和啟動都發生在依賴順序(而不僅僅是啟用/決議),這是解決方案。
請注意,如果您不使用SingleInstance,則將為每個新的依賴項執行個體調用OnActivated。 由於“暖開機”對象通常是單例,建立起來很昂貴,所以這通常是你想要的。