在ASP.NET MVC中使用Unity進行依賴注入的三種方式第一種方法第二種方法第三種方法
在ASP.NET MVC4中,為了在解開Controller和Model的耦合,我們通常需要在Controller啟用系統中引入IoC,用於處理使用者請求的Controller,讓Controller依賴於ModelRepository的抽象而不是它的實現。
我們可以在三個階段使用IoC實現上面所說的解耦操作,首先需要簡單介紹一下預設情況下Controller的啟用過程:
- 使用者傳送請求黑ASP.NET,路由系統對請求進行解析,根據註冊的路由規則對請求進行匹配,解析出Controller和Action的名稱等資訊。
- 將解析出的資訊交給一個MvcRouteHandler物件進行處理,MvcHttpHandler中存在以個ControllerFactory成員,如果建構函式中沒有提供一個實現IControllerFactory介面的物件,則預設建構函式通過呼叫ControllerBuilder.Current.GetControllerFactory()獲取一個這樣的物件。
- 系統呼叫上文物件中德GetHttpHandler獲得了一個實現了IHttpHandler介面的MvcHandler物件最終處理請求。
- 在MvcHandler中呼叫BeginProcessRequest方法繼續處理請求,方法中從1中解析的資訊中獲得Controller和Action的資訊,而後利用2種的IControllerFactory物件啟用Controller物件,並最終執行相應的Action。
第一種方法
由上文2種可知,我們可以建立自己的IControllerFactory物件實現依賴注入,然而我們可以通過直接繼承DefaultControllerFactory並重寫GetControllerInstance方法來實現,這樣可以免去重新實現其他一些功能的工作。
以下是使用Unity建立的繼承自DefaultControllerFactory的UnityControllerFactory的簡單示例:
namespace UnitySample { public class UnityControllerFactory:DefaultControllerFactory { private IUnityContainer container; public UnityControllerFactory(IUnityContainer container) { this.container = container; } protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) { return null == controllerType ? null : (IController)this.container.Resolve(controllerType); //return base.GetControllerInstance(requestContext, controllerType); } } }
我們可以在App_Start中使用ControllerBuilder設定系統使用這個ControllerFactory
IUnityContainer container = new UnityContainer();
container.RegisterType<IXXXRepository, XXXRepository>();
UnityControllerFactory factory = new UnityControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(factory);
第二種方法
上文中繼承的DefaultControllerFactory中,使用一個ControllerActivator的成員來實現對Controller的啟用,如果建立物件中沒有提供一個IControllerActivator物件,則提供一個預設實現了IControllerActivator的DefaultControllerActivator物件這個型別,這個介面中存在用於建立Controller物件的Create方法,在DefaultControllerFactory中有存在一個IControllerActivator型別的構造方法來制定它。所以我們可以使用一個自定義的實現自IControllerActivator藉口的物件來進行依賴注入。
namespace UnitySample
{
public class UnityControllerActivator:IControllerActivator
{
private IUnityContainer container;
public UnityControllerActivator(IUnityContainer container)
{
this.container = container;
}
public IController Create(RequestContext requestContext, Type controllerType)
{
return controllerType == null ? null : (IController)container.RegisterType(controllerType);
}
}
}
修改方法1中在App_Start中的程式碼,使用這個ControllerActivator:
IUnityContainer container = new UnityContainer();
container.RegisterType<IXXXRepository, XXXRepository>();
//UnityControllerFactory factory = new UnityControllerFactory(container);
IControllerActivator controllerActivator = new UnityControllerActivator(container);
DefaultControllerFactory defaultFactory = new DefaultControllerFactory(controllerActivator);
ControllerBuilder.Current.SetControllerFactory(defaultFactory);
第三種方法
如同DefaultControllerFactory類中一樣,在DefaultControllerActivator中也存在一個包含一個引數(型別為IDependencyResolver)的構造方法和一個沒有引數的構造方法,預設情況下DefaultControlerFactory使用無參建構函式例項化一個DefaultControllerActivator物件,這種情況下提供一個預設的IDependencyResolver物件。所以我們就同樣可以使用一個自定義的IDependencyResolver類實現依賴注入。在IDependencyResolver介面中存在方法GetService和GetServices來對具體的型別進行解析
namespace UnitySample
{
public class UnityDependencyResolver:IDependencyResolver
{
private IUnityContainer container;
public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
}
public object GetService(Type serviceType)
{
return container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return container.ResolveAll(serviceType);
}
}
}
修改App_Start中的方法,使用這個自定義的DependencyResolver:
IUnityContainer container = new UnityContainer();
container.RegisterType<IXXXRepository, XXXRepository>();
UnityDependencyResolver resolver = new UnityDependencyResolver(container);
DependencyResolver.SetResolver(resolver);