首页 > 代码库 > IOC 容器在 ASP.NET MVC 中的应用

IOC 容器在 ASP.NET MVC 中的应用

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