日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
自定義的ControllerFactory:接口實現(xiàn),支持Area

幾個星期之前,有個朋友對我說,他的項目中需要將前后臺區(qū)分開來,也就是類似分Area的功能。不過Area只在MVC 2中出現(xiàn),因此現(xiàn)在想在1.0版本中先實現(xiàn)類似的功能了。他打算,根據(jù)Route中捕獲的內容(如“area”),然后去找對應命名空間下的Controller。這樣看來不難,似乎只要在Route上做點配置,而默認的DefaultControllerFactory已經(jīng)對命名空間的查詢提供支持了(可惜有線程安全的問題)。

成都創(chuàng)新互聯(lián)網(wǎng)絡公司擁有10余年的成都網(wǎng)站開發(fā)建設經(jīng)驗,上1000家客戶的共同信賴。提供網(wǎng)站建設、成都網(wǎng)站建設、網(wǎng)站開發(fā)、網(wǎng)站定制、外鏈、建網(wǎng)站、網(wǎng)站搭建、自適應網(wǎng)站建設、網(wǎng)頁設計師打造企業(yè)風格,提供周到的售前咨詢和貼心的售后服務

不過他說,***發(fā)現(xiàn)似乎這塊功能不是他想象的那樣,因此希望我可以看看到底是什么問題。由于當時沒有擴展ASP.NET MVC的需求,后來我事情一多就忘了,現(xiàn)在先說聲抱歉。最近開始對ASP.NET MVC動手動腳了,發(fā)現(xiàn)這樣一個Area的功能非常有用,而且巧合的是,我也打算把Area和命名空間對應起來。

只是我選擇的路和那位兄弟不一樣,我打算自己寫一個簡單的ControllerFactory來替換掉默認的DefaultControllerFactory。這么做的主要原因是:我不知道DefaultControllerFactory已經(jīng)提供對命名空間的支持了,微軟默默地實現(xiàn)了卻沒有對外公開過,我也是后來閱讀代碼時才發(fā)現(xiàn)的。同時又意識到線程安全的問題,于是就還是打算自己寫了。

好在ASP.NET MVC從設計之初就提供了擴展的能力,每個組件粒度都很小,大部分組件都是可以獨立拔插的(Controller類除外,如果你使用自己的IController實現(xiàn),就會發(fā)現(xiàn)大部分功能,如各Filter都失效了)。而要實現(xiàn)一個Controller Factory,只要實現(xiàn)一個簡單的IControllerFactory就可以了(我喜歡接口):

 
 
 
  1. public interface IControllerFactory
  2. {
  3.     IController CreateController(RequestContext requestContext, string controllerName);
  4.     void ReleaseController(IController controller);
  5. }

于是構建一個AreaControllerFactory也大致只需要以下一些代碼:

 
 
 
  1. public class AreaControllerFactory : IControllerFactory
  2. {
  3.     public IController CreateController(RequestContext requestContext, string controllerName)
  4.     {
  5.         ...
  6.     }
  7.     public void ReleaseController(IController controller)
  8.     {
  9.         IDisposable disposable = controller as IDisposable;
  10.         if (disposable != null)
  11.         {
  12.             disposable.Dispose();
  13.         }
  14.     }
  15. }

然后按照慣例,還是一步步談起。首先是構造函數(shù),我們的策略是根據(jù)不同的Area加載不同命名空間下的Controller類型。方便起見,我選擇“基礎命名空間”和“擴展部分”兩塊,它們從構造函數(shù)中傳入:

 
 
 
  1. private Dictionary<stringstring> m_areaPartMapping = new Dictionary<stringstring>();
  2. public string NamespaceBase { getprivate set; }
  3. public AreaControllerFactory(string namespaceBase)
  4.     : this(namespaceBase, null)
  5. { }
  6. public AreaControllerFactory(string namespaceBase, IDictionary<stringstring> areaPartMapping)
  7. {
  8.     this.NamespaceBase = namespaceBase.EndsWith(".") ? namespaceBase : namespaceBase + ".";
  9.     if (areaPartMapping != null)
  10.     {
  11.         foreach (var pair in areaPartMapping)
  12.         {
  13.             this.m_areaPartMapping.Add(pair.Key.ToLowerInvariant(), pair.Value);
  14.         }
  15.     }
  16. }

于是我們就可以這樣使用:

 
 
 
  1. var controllerFactory = new AreaControllerFactory("MyApp.Controllers");
  2. ControllerBuilder.Current.SetControllerFactory(controllerFactory);

如果在需要的時候,還可以指定Area與特定命名空間“部分”的映射關系。因此,我們需要從Area來獲取這個“Part”:

 
 
 
  1. private string GetNamespacePart(string area)
  2. {
  3.     if (String.IsNullOrEmpty(area)) return "";
  4.     string part;
  5.     if (this.m_areaPartMapping.TryGetValue(area.ToLowerInvariant(), out part))
  6.     {
  7.         return part;
  8.     }
  9.     return area;
  10. }

這里我選擇“配置”和“約定”相結合的方式。得到一個Area之后,我們會在映射表里進行查找Part,如果沒有,則Area本身便是Part。根據(jù)Part和Controller名稱,我們便可以獲得Controller的類型:

 
 
 
  1. private ReaderWriterLockSlim m_rwLock = new ReaderWriterLockSlim();
  2. private Dictionary<string, Type> m_controllerTypes = new Dictionary<string, Type>();
  3. private Type GetControllerType(string area, string controllerName)
  4. {
  5.     string part = this.GetNamespacePart(area);
  6.     string typeName = String.IsNullOrEmpty(part) ?
  7.         this.NamespaceBase + controllerName.ToLowerInvariant() + "Controller" :
  8.         this.NamespaceBase + part + "." + controllerName.ToLowerInvariant() + "Controller";
  9.     Type type;
  10.     this.m_rwLock.EnterReadLock();
  11.     try
  12.     {
  13.         if (this.m_controllerTypes.TryGetValue(typeName, out type))
  14.         {
  15.             return type;
  16.         }
  17.     }
  18.     finally
  19.     {
  20.         this.m_rwLock.ExitReadLock();
  21.     }
  22.     type = Type.GetType(typeName, falsetrue);
  23.     if (type != null)
  24.     {
  25.         this.m_rwLock.EnterWriteLock();
  26.         try
  27.         {
  28.             this.m_controllerTypes[typeName] = type;
  29.         }
  30.         finally
  31.         {
  32.             this.m_rwLock.ExitWriteLock();
  33.         }
  34.     }
  35.     return type;
  36. }

由于我選擇在應用程序中使用同一個AreaControllerFactory對象,因此線程安全是一定要有保證的。這里我們用到了讀寫鎖,不過請注意,紅色那句話并不保證對于每個相同的typeName只執(zhí)行一次,也不保證相同的typeName對于m_controllerTypes字典只會進行一次寫操作(所以我沒有Add,而是使用了下標操作)。不過,由于這些“重復”不會造成問題,因此就沒有去涉及太多這方面的考慮。

***,便是那CreateControlle方法:

 
 
 
  1. public IController CreateController(RequestContext requestContext, string controllerName)
  2. {
  3.     Type controllerType;
  4.     object area;
  5.     if (requestContext.RouteData.Values.TryGetValue("area", out area))
  6.     {
  7.         controllerType = this.GetControllerType(area.ToString(), controllerName);
  8.     }
  9.     else
  10.     {
  11.         controllerType = this.GetControllerType(null, controllerName);
  12.     }
  13.     if (controllerType == null)
  14.     {
  15.         throw new HttpException(404,
  16.             String.Format(
  17.                 "Controller of path {0} not found.",
  18.                 requestContext.HttpContext.Request.Path));
  19.     }
  20.     try
  21.     {
  22.         return (IController)Activator.CreateInstance(controllerType);
  23.     }
  24.     catch (Exception ex)
  25.     {
  26.         string message = String.Format("Error creating controller {0}" + controllerType);
  27.         throw new InvalidOperationException(message, ex);
  28.     }
  29. }

似乎沒有什么可談的:我們從RouteData中獲取出area對應的值,并且調用GetControllerType方法獲得Controller的類型,并使用Activator.CreateInstance創(chuàng)建對象。在不合法的情況下,拋出合適的異常即可。

至此,AreaControllerFactory就完成了,很容易,不是嗎?很顯然,這個組件的功能非常有限,例如為什么所有的Controller一定要在同一個命名空間下?沒錯,它其實只是符合“我要求”的一個東西。但是,在項目中很多東西都是如此,我只實現(xiàn)我夠用的功能。例如,我可能不會向對外公開的API那樣,嚴格檢查每個問題,拋出嚴謹?shù)漠惓!N铱赡軆A向于在項目中使用接口,而不是使用抽象類。因為是我的項目,我可以快速反饋,需要修改的時候就修改吧。

同樣的,如果DefaultControllerFactory真在某些特別情況下有問題,或者支持的有些復雜。那么不如我們就自己動手吧。一次性投入,而且這樣的小組件也花不了多少時間。

本文來自老趙點滴:《支持Area的ControllerFactory》


新聞名稱:自定義的ControllerFactory:接口實現(xiàn),支持Area
URL鏈接:http://m.5511xx.com/article/djsopcj.html