Autofac 可以協助達成 IOC、DI 的目的,內部如何達成可以參考此篇"Autofac 套件如何達成IOC 目的- 概述圖解" 內容。套件也可以協助幫忙達成MVC架構的DI,使用上其實非常方便。但在一番了解 Autofac 初步的運作後,有些想知道運作原理傾向的開發者大多也會對如何達成 .NET MVC 之 DI 這個原理有些好奇,怎麼對MVC Controller建構子參數做Resolve的?
所以概述如何做到DI的目的,會分以下順序
以下會進行相關描述:
1. 如何於 .NET MVC 架構使用Autofac
首先要先於 .NET MVC 專案安裝 Autofac.Integration.Mvc 套件。安裝完成後,一樣要先在 Global.asax.cs 的 Application_Start 進行設定,對 MVC Controller 的類別註冊服務。程式為:
var builder = new Autofac. ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
然後控制項類別註冊後,接著可為這些類別所要使用的物件做註冊服務。舉個例子,於 HomeController,加上一個有參數的建構子(另外有一個ILog的欄位成員):
ILog log;
public HomeController(ILog pLog){
log = pLog;
...
}
如果沒有DI的協助,我們需要在每個類別中某處去做
ILog log = new ClsLog();
但是如果有幾十個Controller都要用到此ClsLog物件,如果某天要換物件的名稱內容,避免不了要改幾十次,開發效率就降低了。
所以我們要 Autofac DI 的協助。接著進行 ClsLog 的註冊服務:
builder.RegisterType<ClsLog>().As<ILogC>();
最後,建立容器與完成服務最終註冊:
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
DependencyResolver 是 System.Web.Mvc的物件,AutofacDependencyResolver 是 Autofac.Integration.Mvc的物件。 這邊建構好 Autofac 容器後,只要叫用到 HomeController都會注入 ClsLog 實體給建構子參數。
2. MVC 架構生成 Controller 之過程圖解
那Autofac如何對MVC Controller建構子參數做Resolve的?
首先要研究MVC是如何產生Controller。下圖為 MVC 5 產生Controller 實體的過程簡圖:
上圖中,紅色框部分是產生Controller實體的關鍵時間點。MvcHandler會去取得生成 Controller 的 Factory,此Factory之前的初始化會建構 DependencyResolver,將 Controller 類別依照 Type 來產生實體,更進一步使用的是 System.Reflection組件。
3. Autofac 如何於MVC辦到DI之簡述
如果AutoFac 要進行切入,勢必要於上一點提到的這個關鍵的時間點,改讓Autofac來做Resolve,將建構子參數做遞迴的Resolve (參考"Autofac 套件如何達成IOC 目的- 概述圖解")。
Autofac.Integration.Mvc 組件也改寫了套用 IDependencyResolver 的類別,將 GetService 改為由 Autofac組件的擴增函式來執行:
public virtual object GetService(Type serviceType)
{
return ResolutionExtensions.ResolveOptional(this.RequestLifetimeScope, serviceType);
}
於是,Controller的Type被送入後,接著就會跑 Autofac 組件的 TryResolveService、ResolveComponent,然後遞迴將建構子的參數再進行Resolve。
而什麼時候會替換Autofac.Integration.Mvc的這個 IDependencyResolver 內容? 就是第一點說明的建立容器與完成服務最終註冊:
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
這邊會將 IDependencyResolver 進行替換。
4.以簡單的例子作範例
看到這邊應該多少了解關鍵的時間點替換由Autofac來接手做Resolve Controller類別,至少知道有這件事的存在。
用簡單的例子,來實現 MVC Controller Constructor Parameter DI
於 Global.asax.cs 的 Application_Start 進行設定:
最後Controller建構子會接到所註冊的Service:
如上參數的實體記憶體為 ClsLog 這個類別的型態。
以上是 Autofac 如何利用 Autofac.Integration.Mvc 組件來實行對 .NET MVC 的 Controller 建構子參數作 DI,希望能夠協助幫助,想要知道真相是如何運作的人,基礎的入門重點。