標籤:style blog class code c tar
經過上篇蜻蜓點水的介紹後,本篇通過執行個體快速上手autofac,展示當asp.net mvc引入了autofac之後會帶來什麼。
建立Asp.net MVC並引入Autofac
首先,建立一個MVC網站,為方便起見,選初始帶HomeController和AccountController的那種。然後通過NuGet或到Autofac官網下載來引入類庫。個人推薦前者,因為從VS2010開始,已內集可視化的NuGet功能,使用起來非常方便。如所示:
這是vs2012的介面,點擊“Manage NuGet Packages…”,彈出表單如下,在右上方搜尋方塊中輸入“Autofac”,找到對應的庫點擊安裝即可。這裡需要應用的庫有兩個“Autofac”和“Autofac ASP.Net MVC3 Integration”。
autofac實現對Controller的自動注入
現在HomeController需要用到日誌記錄功能。沿用上篇ILog介面,假設目前已有一種ILog的實作類別--TxtLog,放在根目錄下Services檔案夾中。
雙擊代碼全選
| 1 2 3 4 5 6 7 |
public class TxtLog:ILog { public void Save(string message) { //save as txt } } |
HomeController需添加一個ILog類型變數,為了直觀看到類名,我把_log的類名賦給ViewBag.LogTypeName並顯示出來。代碼如下:
雙擊代碼全選
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class HomeController : Controller { private ILog _log; public HomeController(ILog log) { _log = log; } public ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!"; ViewBag.LogTypeName = _log.GetType().Name; return View(); } //.... |
接著,在對應頁面加入以下代碼(抱歉這裡用英文描述,因為My Code高亮外掛程式不能顯示中文):
<h2>ILog‘s type name is @ViewBag.LogTypeName</h2>
此時運行程式會報錯,因為HomeController找不到無參建構函式,而我們也沒有給_log指定任何類型的執行個體。
現在我們讓Autofac發揮作用,在Global檔案的Application_Start方法中添加配置代碼,如下:
雙擊代碼全選
| 1 2 3 4 5 6 7 8 9 10 11 12 |
protected void Application_Start() { ...... ContainerBuilder builder = new ContainerBuilder(); builder.RegisterControllers(Assembly.GetExecutingAssembly()); builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()) .AsImplementedInterfaces(); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); } |
先不管含義,加了這些代碼以後,再運行程式,會發現HomeController的ILog變數被賦予了TxtLog類型的執行個體,而我們並沒有做任何new操作,結果如:
autofac應對需求變更
回頭再看Application_Start中設定檔的代碼:
-
builder.RegisterControllers註冊了當前程式集內所有的Controller類。
-
builder.RegisterAssemblyTypes註冊了當前程式集內的所有類。
如果此刻需求改變,我們需要將所有的TxtLog換成DbLog,該怎麼辦?首先添加DBLog類,如下:
雙擊代碼全選
| 1 2 3 4 5 6 7 |
public class DbLog:ILog { public void Save(string message) { //save to Db. } } |
然後在Application_Start的方法的末端處添加如下代碼:
雙擊代碼全選
| 1 |
builder.RegisterType<DbLog>().As<ILog>(); |
運行程式,看到頁面如下:
可看出ILog的類型已變成了DbLog。但為何要強調末端處?實際上,DBLog已經通過builder.RegisterAssemblyTypes被註冊過一次,如果對同一個類型或介面註冊多次(比如這裡的ILog),在Autofac中會以列表的形式儲存,如果只取一個,則Autofac會從列表返回最新的那個。
為了證明,我們在HomeController中再加入一個變數,類型為IEnumerable<ILog>,然後將列表中所有類名顯示出來,用逗號隔開。
雙擊代碼全選
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class HomeController : Controller { private ILog _log; private IEnumerable<ILog> _logList; public HomeController(ILog log,IEnumerable<ILog> logList ) { _log = log; _logList = logList; } public ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!"; ViewBag.LogTypeName = _log.GetType().Name; ViewBag.LogTypeNames = _logList.Select(x => x.GetType().Name).Aggregate((x, y) => x+","+y ); return View(); } |
運行程式,頁面顯示如下:
可以看到,針對ILog介面註冊了三個類型。前兩個通過builder.RegisterAssemblyTypes註冊,最後一個是我們手動添加。
但重複的註冊類型總讓人覺得不夠優雅,因此實際開發中並不推薦一次性註冊所有類,可條件式篩選。翻開Autofac的源碼,查看我們上文用到的builder.RegisterControllers會探索方法內部就是這種思路:
雙擊代碼全選
| 1 2 3 4 5 6 7 8 9 |
public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterControllers( this ContainerBuilder builder, params Assembly[] controllerAssemblies) { return builder.RegisterAssemblyTypes(controllerAssemblies) .Where(t => typeof(IController).IsAssignableFrom(t) && t.Name.EndsWith("Controller")); } |
由代碼可知,該方法篩選出所有實現IController介面且類型名以“Controller”結尾的類。你可以根據自己項目的實際情況來篩選,很多使用Autofac的開來源站點點也都是這麼做的。
結語
未完,待續……^_^