[翻譯] Autofac 入門文檔
原文鏈接: http://docs.autofac.org/en/latest/getting-started/index.html
在程序中使用Autofac的基本模式是:
- 用控制反轉(IoC)的思想組織程序。
- 添加對 Autofac 的引用。
- 程序啟動階段
- 創建 ContainerBuilder 。
- 注冊組件。
- 生成容器。
- 程序執行階段
- 從容器創建生命周期范圍對象( ILifetimeScope 接口)。
- 使用生命周期范圍對象解析組件實例。
本文通過一個簡單的控制臺程序演示這些步驟。
組織程序
控制反轉的基本思路是,不讓類創建它的依賴項,而是將依賴項通過構造函數傳遞給它。請參閱 Martin Fowler 這篇解釋依賴注入/控制反轉的文章。
在本示例中,我們定義一個輸出“今天”的日期的類。但是,我們不想讓它和 Console 類捆綁在一起。這有兩個原因:1,方便測試,2,在沒有Console的環境中也能使用。
我們還對輸出日期的方式進行抽象,這樣就可以隨時切換到另一個版本,比如輸出“明天”的日期。
代碼:
using System; namespace DemoApp { // 此接口將“輸出”概念從Console類解耦。 // 我們只管“輸出”,而不關心操作是怎么進行的。 public interface IOutput { void Write(string content); } // 這里的實現方式是向Console輸出內容。 // 也可以用其他方式,比如輸出到 Debug 和 Trace。 public class ConsoleOutput : IOutput { public void Write(string content) { Console.WriteLine(content); } } // 這個接口將“輸出日期”的概念從具體的輸出方法中解耦。 public interface IDateWriter { void WriteDate(); } // TodayWriter 是這些元素匯合在一起的地方。 // 它的構造函數有一個 IOutput 參數,通過提供不同的實現類, // TodayWriter可以將日期寫到不同的地方。 // 進一步的,在這里WriteDate的實現方式是輸出“今天的日期”, // 我們可以用另一個類輸出其他格式,或者其他日期。 public class TodayWriter : IDateWriter { private IOutput _output; public TodayWriter(IOutput output) { this._output = output; } public void WriteDate() { this._output.Write(DateTime.Today.ToShortDateString()); } } }
現在我們有了組織良好的依賴關系,接下來引入 Autofac。
添加對 Autofac 的引用
首先向項目添加對Autofac的引用。這個示例中,我們只使用 Autofac 的核心部分。其他類型的應用程序可能需要Autofac 集成庫。
最簡單的方式是使用 NuGet。“Autofac” 程序包包含所有核心功能。
程序啟動階段
我們在程序啟動時創建 ContainerBuilder 對象,然后向它注冊組件。組件可以是表達式,.NET 類型, 或者其他暴露服務的代碼。組件可以接受其他依賴項。
假設有下面的.net類型:
public class SomeType : IService { }
我們有兩種使用它的方式:
- 作為這個類型本身, SomeType
- 作為接口, IService
因此, 這里的組件是 SomeType,它暴露的服務是 SomeType 和 IService。
在 Autofac 中,使用 ContainerBuilder 注冊組件:
// 創建builder var builder = new ContainerBuilder(); // 通常僅通過接口暴露服務 builder.RegisterType<SomeType>().As<IService>(); // 但是, 如果同時需要兩種服務(不常見),可以用這種方式: builder.RegisterType<SomeType>().AsSelf().As<IService>();
在示例程序中,我們要注冊全部組件(類)并暴露他們的服務 (接口),以便他們能連接起來。
我們還需要把容器保存起來,以便稍后使用它解析類型。
using System; using Autofac; namespace DemoApp { public class Program { private static IContainer Container { get; set; } static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType<ConsoleOutput>().As<IOutput>(); builder.RegisterType<TodayWriter>().As<IDateWriter>(); Container = builder.Build(); // The WriteDate method is where we'll make use // of our dependency injection. We'll define that // in a bit. WriteDate(); } } }
現在,容器里注冊了全部所需的組件和服務,接下來我們來使用它進行解析。
程序執行階段
程序執行時,通過從 生存范圍 對象解析并使用組件。
容器本身即是一個 生存范圍 對象,因此可以從容器直接解析類型,但是并 不推薦這么做 。
解析組件時,根據定義的 實例范圍 創建一個新的實例。(解析組件類似于使用new操作符) 有些組件需要清理 (比如實現IDisposable接口) -當 生存范圍 對象被清理時,Autofac 可以同時清理它解析的組件。
由于容器對象的生命周期與應用程序相同,如果從容器直接解析了大量內容, 未處理的組件就會越積越多,從而造成資源泄露。
相反,我們從容器創建一個 生存范圍 對象,然后通過 生存范圍 來解析對象,清理生存范圍對象時,從中解析的組件也一同被清理。
(使用 Autofac 集成庫時,子范圍通常會自動創建。)
對于本示例,“WriteDate” 方法從范圍對象獲取對象,使用結束時只要清理范圍對象。
namespace DemoApp { public class Program { private static IContainer Container { get; set; } static void Main(string[] args) { // ...the stuff you saw earlier... } public static void WriteDate() { // Create the scope, resolve your IDateWriter, // use it, then dispose of the scope. using (var scope = Container.BeginLifetimeScope()) { var writer = scope.Resolve<IDateWriter>(); writer.WriteDate(); } } } }
程序的執行過程如下:
- “WriteDate” 方法向 Autofac 請求 IDateWriter 實例。
- Autofac 發現 IDateWriter 映射到 TodayWriter ,于是準備創建一個 TodayWriter 實例。
- Autofac 發現 TodayWriter 的構造函數需要一個IOutput 實例。
- Autofac 發現 IOutput 映射到 ConsoleOutput,于是創建一個ConsoleOutput實例。
- Autofac 使用 ConsoleOutput 實例完成 TodayWriter 的創建。
- Autofac 返回 TodayWriter。
想輸出另一個日期時,可以實現另一個 IDateWriter,然后更改啟動階段的注冊內容,而不需要更改其他類。這就是控制反轉。
注意: 一般而言,普遍認為服務定位是反模式。 (see article) 換言之,隨處手工創建范圍對象,在代碼中零散的使用容器對象是不好的方式。通過使用Autofac 集成庫 ,可以避免示例代碼中的使用方式。相反,內容在一個位置集中解析,也就是在程序的 “最頂層”位置,極少需要進行手工解析。
更進一步
示例演示了如何使用 Autofac, 您可以繼續了解:
- 查看 集成庫 列表,了解怎樣將 Autofac 集成到程序。
- 了解 注冊組件的方式 。
- 了解 Autofac 配置 選項 ,對組件注冊進行管理。
來自: http://www.cnblogs.com/dongbeifeng/p/autofac-getting-started.html