IOC:Inversion Of Control 翻譯為控制反轉,我們在面向對象軟件開發過程中,一個應用程序它的底層結構可能由N種不同的構件來相互協作來完成我們定義的系統的業務邏輯。哪么每一個構件可能相互獨立和相互依賴,如果相互依賴的構件中的某一個構件出現異常,就會影響到整個系統的穩定運行,對象之間的耦合關系是無法避免的,也是必要的,因為這是協同工作的基礎。如何降低系統之間、模塊之間和對象之間的耦合度,是軟件工程永遠追求的目標之一。為了解決對象之間的耦合度過高的問題,IOC 的理念被提出,並被成功地應用到實踐當中。說直白一點,就是對象之間的創建與維護我們全權交給了外部容器來管理,這樣就實現了所謂的反轉。
.NET 體系下這些相對成熟輕量級的IOC 容器,Castle Windsor、Unity、Spring.NET、StructureMap和Ninject等,下面我們就開始演示IOC在ASP.NET MVC 下的應用,在這里我們選擇 Castle 來做為 IOC 容器。ASP.NET MVC 的 Controller 激活是靠ControllerFactory來創建的Controller對象的,所以我們就直接創建一個WindsorControllerFactory類,通過繼承自DefaultControllerFactory來實現Controller的實例創建解析和釋放等功能。
1 using Castle.Core.Resource; 2 using Castle.Windsor; 3 using Castle.Windsor.Configuration.Interpreters; 4 using System; 5 using System.Linq; 6 using System.Reflection; 7 using System.Web.Mvc; 8 9 namespace mvc_with_Castle.App_Start 10 { 11 public class WindsorControllerFactory : DefaultControllerFactory 12 { 13 private WindsorContainer container; 14 public WindsorControllerFactory() 15 { 16 container = new WindsorContainer( 17 new XmlInterpreter(new ConfigResource("castle")) 18 ); 19 20 var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes() 21 where typeof(IController).IsAssignableFrom(t) 22 select t; 23 foreach (Type t in controllerTypes) 24 container.AddComponentLifeStyle(t.FullName, t, Castle.Core.LifestyleType.Transient); 25 } 26 27 protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) 28 { 29 return (IController)container.Resolve(controllerType); 30 } 31 } 32 }
一個自定義的WindsorControllerFactory就這么簡單的創建完了,下一步創建一個基於 IWindsorInstaller 的對容器的安裝類
using Castle.MicroKernel.Registration; using Castle.MicroKernel.SubSystems.Configuration; using System.Web.Mvc; namespace mvc_with_Castle.App_Start { public class ControllersInstaller : IWindsorInstaller { public void Install(Castle.Windsor.IWindsorContainer container, IConfigurationStore store) { container.Register(Classes.FromThisAssembly() .BasedOn<IController>() .LifestyleTransient().Configure(c => c.DependsOn())); } } }
接下來我們對Global.asax做一些修改,注冊我們默認的 WindsorControllerFactory 控制器工廠類。
1 using Castle.Windsor; 2 using Castle.Windsor.Installer; 3 using mvc_with_Castle.App_Start; 4 using System.Web.Mvc; 5 using System.Web.Optimization; 6 using System.Web.Routing; 7 8 namespace mvc_with_Castle 9 { 10 public class MvcApplication : System.Web.HttpApplication 11 { 12 private static IWindsorContainer container; 13 private static void MyContainer() 14 { 15 container = new WindsorContainer().Install(FromAssembly.This()); 16 17 var controllerFactory = new WindsorControllerFactory(); 18 ControllerBuilder.Current.SetControllerFactory(controllerFactory); 19 } 20 protected void Application_Start() 21 { 22 AreaRegistration.RegisterAllAreas(); 23 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 24 RouteConfig.RegisterRoutes(RouteTable.Routes); 25 BundleConfig.RegisterBundles(BundleTable.Bundles); 26 27 MyContainer(); 28 } 29 30 protected void Application_End() 31 { 32 container.Dispose(); 33 } 34 } 35 }
所有的准備工作差不多都准備完畢,接下來我們就來定義一個接口實現對人員的查詢
1 using System.Collections.Generic; 2 3 namespace mvc_with_Castle.Service 4 { 5 public class SysUser 6 { 7 public string Name { get; set; } 8 9 public string Sex { get; set; } 10 11 public string Phone { set; get; } 12 13 public string Address { get; set; } 14 15 public string Email { get; set; } 16 } 17 18 public interface IUsersSvr 19 { 20 IEnumerable<SysUser> QueryUsers(); 21 } 22 23 public class UsersSvr : IUsersSvr 24 { 25 private static IList<SysUser> list; 26 27 static UsersSvr() 28 { 29 list = new List<SysUser>(); 30 for (int i = 0; i < 10; i++) 31 { 32 list.Add(new SysUser() 33 { 34 Name = "如花" + i, 35 Sex = "男", 36 Phone = "13882880818", 37 Address = "皇后大道中段" + i + "號", 38 Email = "jack@gmail.com" 39 }); 40 } 41 } 42 43 public IEnumerable<SysUser> QueryUsers() 44 { 45 return list; 46 } 47 } 48 }
再下來就是我們對Castle IOC的配置管理
1 <configSections> 2 <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/> 3 </configSections> 4 5 <!--注冊服務--> 6 <castle> 7 <components> 8 <component id="UsersSvr" type="mvc_with_Castle.Service.UsersSvr, mvc_with_Castle" service="mvc_with_Castle.Service.IUsersSvr, mvc_with_Castle" lifestyle="Singleton"/> 9 </components> 10 </castle>
最后調用我們定義的 IUserSvr 接口來實現查詢數據
1 using System.Collections.Generic; 2 using System.Web.Mvc; 3 using mvc_with_Castle.Service; 4 5 namespace mvc_with_Castle.Controllers 6 { 7 public class HomeController : Controller 8 { 9 public IUsersSvr _svr { get; set; } 10 public ActionResult Index() 11 { 12 IEnumerable<SysUser> list = _svr.QueryUsers(); 13 return View(list); 14 } 15 } 16 }
人員信息顯示效果如下
在這里我們已經大概了解了什么是IOC容器,和在 ASP.NET MVC 下面我們怎樣利用 IOC 容器來實現通過接口的方式來進行服務的調用的大致原理,在上面的HomeController里面,很明顯我們不用擔心接口怎么被實例化的,或者說我們沒明白服務到底怎么被激活了,哪么再回頭看看前面的代碼是不是就一目了然了呢 ?