閱讀475 返回首頁    go 阿裏雲 go 技術社區[雲棲]


為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應用的主頁,將會得到如下所示的聯係人列表。

image


作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接

最後更新:2017-10-26 14:34:10

  上一篇:go  集成EntLib實現ASP.NET MVC的異常處理
  下一篇:go  《WCF技術剖析(卷2)》目錄