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里面,很明显我们不用担心接口怎么被实例化的,或者说我们没明白服务到底怎么被激活了,哪么再回头看看前面的代码是不是就一目了然了呢 ?