平常用Inject比較多,今天接觸到了Castle Windsor。本篇就來體驗其在ASP.NET MVC中的應用過程。
Visual Studio 2012創建一個ASP.NET MVC 4網站。
通過NuGet安裝Castle Windsor。
在當前項目下創建一個名稱為"IOC"的文件夾。
在ASP.NET MVC中,每次請求,DefaultControllerFactory都會為我們創建controller實例,我們需要自定義一個派生自DefaultControllerFactory的類,讓Castle Windsor幫我們生成controller實例。
using System.Web;using System.Web.Mvc;using Castle.MicroKernel;namespace MyCastleWindsor.IOC{public class WindsorControllerFactory : DefaultControllerFactory{private readonly IKernel _kernel;public WindsorControllerFactory(IKernel kernel){_kernel = kernel;}protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, System.Type controllerType){if (controllerType == null){throw new HttpException(404,string.Format("當前對{0}的請求不存在",requestContext.HttpContext.Request.Path));}return (IController)_kernel.Resolve(controllerType);}public override void ReleaseController(IController controller){_kernel.ReleaseComponent(controller);base.ReleaseController(controller);}}}
現在需要在全局中生成Castle Windsor實例,賦值給自定義ControllerFactory的構造函數,並在Application結束時銷毀該Castle Windsor實例。
public class MvcApplication : System.Web.HttpApplication{private IWindsorContainer _container;protected void Application_Start(){AreaRegistration.RegisterAllAreas();WebApiConfig.Register(GlobalConfiguration.Configuration);FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);RouteConfig.RegisterRoutes(RouteTable.Routes);BundleConfig.RegisterBundles(BundleTable.Bundles);//初始化一個IOC容器_container = new WindsorContainer().Install(FromAssembly.This());//完成IWindsorInstaller接口中的注冊ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(_container.Kernel));}protected void Application_End(){_container.Dispose();}}
現在,需要告訴Castle Windsor在何種條件下,以怎樣的方式注冊依賴。Castle Windsor提供了IWindsorInstaller接口。在IOC文件夾下創建實現該接口的類。
using System.Web.Mvc;using Castle.MicroKernel.Registration;using MyCastleWindsor.Controllers;namespace MyCastleWindsor.IOC{public class ControllerInstaller : IWindsorInstaller{public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store){container.Register(Classes.FromThisAssembly() //在哪里找尋接口或類.BasedOn<IController>() //實現IController接口.If(Component.IsInSameNamespaceAs<HomeController>()) //與HomeController在同一個命名空間.If(t => t.Name.EndsWith("Controller")) //以"Controller"結尾.Configure(c => c.LifestylePerWebRequest()));//每次請求創建一個Controller實例}}}
而實際上,在全局文件中,當運行Install(FromAssembly.This())方法時,會執行 IWindsorInstaller的Install接口方法。
舉例來說
假設有一個接口:
public interface IContactManager{}
接口的實現類:
public class ContactManager : IContactManager{}
在某個控制器中,通過構造函數注入依賴,我們希望這樣寫:
private IContactManager contactManager;public HomeController(IContactManager contactManager){this.contactManager = contactManager;}
現在需要注冊IContactManager和ContactManager。可以通過反射方式注冊依賴。
using System.Web.Mvc;using Castle.MicroKernel.Registration;using MyCastleWindsor.Controllers;namespace MyCastleWindsor.IOC{public class ControllerInstaller : IWindsorInstaller{public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store){container.Register(Classes.FromThisAssembly().Where(t => t.Name.EndsWith("Manager")).WithServiceDefaultInterfaces().Configure(c => c.LifestyleTransient()));}}}
關於Castle Windsor的應用大致如下:
→ 繼承ASP.NET MVC的ControllerFactory,通過構造函數傳入Castle Windsor的IKernel,讓其解析出IController類型控制器。
→ 通過實現Castle Windsor的IWindsorInstaller接口,通過反射注冊依賴關系。
→ 在全局文件中初始化Castle Windsor的實例,並注冊自定義的ControllerFactory。