为ASP.NET MVC创建一个基于Unity的ControllerFactory
谈到IoC和ASP.NET的集成,很多人会先后想到Ninject,不过我们个人还是倾向于Unity。这篇文章简单地介绍如果创建基于Unity的ControllerFactory。如下面的代码所示,我们通过直接继承DefaultControllerFactory创建一个自定的UnityControllerFactory。构造函数指定的是配置的UnityContainer的名称,如果没有显式指定则采用默认的UnityContainer。在重写的GetControllerInstance方法中,直接调用IUnityContainer的Resolve方法根据Controller类型创建相应的对象。[源代码从这里下载]
1: public class UnityControllerFactory: DefaultControllerFactory
   2: {
    3: public IUnityContainer Container { get; private set; }
4: public UnityControllerFactory(string containerName = "")
   5:     {
    6: IUnityContainer container = new UnityContainer();
7: UnityConfigurationSection configSection = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;
8: if (null == configSection && !string.IsNullOrEmpty(containerName))
   9:         {
    10: throw new ConfigurationErrorsException("Cannot find <unity> configuration section");
  11:         }
      12:  
    13: if (string.IsNullOrEmpty(containerName))
  14:         {
      15:             configSection.Configure(container);
      16:         }
    17: else
  18:         {
      19:             configSection.Configure(container, containerName);
      20:         }
    21: this.Container = container;
  22:     }
    23: protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
  24:     {
    25: Guard.ArgumentNotNull(controllerType, "controllerType");
26: return (IController)this.Container.Resolve(controllerType);
  27:     }
      28: }
为了演示DefaultControllerFactory的作用,我们来创建一个简单的例子。假设我们要创建一个维护联系人的应用,我们通过具有如下定义的Contact类型表示联系人,而IContactRepository接口定义了一个从存储中获取所有联系人的GetAllContacts方法,DefaultContactRepository是对IContactRepository接口的实现。
1: public class Contact
   2: {
    3: public string Name { get; set; }
4: public string Gender { get; set; }
5: public string Address { get; set; }
   6: }
       7:  
    8: public interface IContactRepository
   9: {
      10:     IEnumerable<Contact> GetAllContacts();
      11: }
      12:  
    13: public class DefaultContactRepository : IContactRepository
  14: {
    15: public IEnumerable<Contact> GetAllContacts()
  16:     {
    17: yield return new Contact
  18:         {
    19: Name = "Zhang San",
20: Gender = "Male",
21: Address = "#328, XingHu Street, Su Zhou, Jiang Su Province, PRC."
  22:         };
      23:  
    24: yield return new Contact
  25:         {
    26: Name = "Li Si",
27: Gender = "Female",
28: Address = "#328, Jin Ji Hu Road, Su Zhou, Jiang Su Province, PRC."
  29:         };
      30:     }
      31: }
我们在Web应用的主页显示联系人列表,为此我创建了如下一个HomeController。在这里我们演示的是构造器注入,所以我们通过构造函数指定的IContactRepository对象来初始化Repository属性。在Action方法Index中调用IContactRepository的GetAllContacts方法为对应的View指定Model。
1: public class HomeController : Controller
   2: {
    3: public IContactRepository Repository { get; private set; }
4: public HomeController(IContactRepository repository)
   5:     {
    6: this.Repository = repository;
   7:     }
    8: public ActionResult Index()
   9:     {
    10: return View(this.Repository.GetAllContacts());
  11:     }
      12: }
Index.cshtml代码如下所示,这是一个Model类型为IEnumerable<Contact>的View,它将所有的联系人信息列出来。
1: @model IEnumerable<Artech.Web.Mvc.Extensions.Contact>
   2: @{
       3:     ViewBag.Title = "Index";
       4: }
       5:  
    6: <h2>Contact List</h2>
   7:  
    8: <div>
9: <ul>
  10: @foreach (var contact in this.Model)
      11: { 
    12: <li>
13: <h3>@contact.Name</h3>
14: <p>Gender: @contact.Gender</p>
15: <p>Address: @contact.Address</p>
16: <hr />
17: </li>
  18: }
    19: </ul>
20: </div>
自定义的UnityContainerFactory的注册定义在Gloable.asax中。初次之外,额外需要做的是忽略掉针对favicon.ico的路由,否则程序运行将会失败。
1: public class MvcApplication : System.Web.HttpApplication
   2: {
    3: public static void RegisterGlobalFilters(GlobalFilterCollection filters)
   4:     {
    5: filters.Add(new HandleErrorAttribute());
   6:     }
       7:  
    8: public static void RegisterRoutes(RouteCollection routes)
   9:     {
    10: routes.IgnoreRoute("favicon.ico");
11: routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
12: routes.MapRoute("Default", "{controller}/{action}/{id}",
13: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  14:         );
      15:     }
      16:  
    17: protected void Application_Start()
  18:     {
      19:         AreaRegistration.RegisterAllAreas();
      20:         RegisterGlobalFilters(GlobalFilters.Filters);
      21:         RegisterRoutes(RouteTable.Routes);
      22:  
    23: ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory());
  24:     }
      25: }
接口IContactRepository和DefualtContactRepository之间的映射关系定义在如下所示的<unity>配置中。
1: <unity>
2: <alias alias="IContactRepository" type="Artech.Web.Mvc.Extensions.IContactRepository, UnityIntegration" />
3: <alias alias="DefaultContactRepository" type="Artech.Web.Mvc.Extensions.DefaultContactRepository, UnityIntegration" />
4: <container>
5: <register type="IContactRepository" mapTo="DefaultContactRepository"/>
6: </container>
7: </unity>
通过浏览器访问Web应用的主页,将会得到如下所示的联系人列表。


谈到IoC和ASP.NET的集成,很多人会先后想到Ninject,不过我们个人还是倾向于Unity。这篇文章简单地介绍如果创建基于Unity的ControllerFactory。
    
                
            
        
浙公网安备 33010602011771号