成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

自定義的ControllerFactory:接口實現,支持Area

開發 后端
作者編寫了一個簡單的ControllerFactory來替換掉默認的DefaultControllerFactory,這個ControllerFactory可以實現Area功能。

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

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

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

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

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

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

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

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

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

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

  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.  
  5.     string part;  
  6.     if (this.m_areaPartMapping.TryGetValue(area.ToLowerInvariant(), out part))  
  7.     {  
  8.         return part;  
  9.     }  
  10.  
  11.     return area;  
  12. }  
  13.  

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

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

由于我選擇在應用程序中使用同一個AreaControllerFactory對象,因此線程安全是一定要有保證的。這里我們用到了讀寫鎖,不過請注意,紅色那句話并不保證對于每個相同的typeName只執行一次,也不保證相同的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.  
  14.     if (controllerType == null)  
  15.     {  
  16.         throw new HttpException(404,  
  17.             String.Format(  
  18.                 "Controller of path {0} not found.",  
  19.                 requestContext.HttpContext.Request.Path));  
  20.     }  
  21.  
  22.     try 
  23.     {  
  24.         return (IController)Activator.CreateInstance(controllerType);  
  25.     }  
  26.     catch (Exception ex)  
  27.     {  
  28.         string message = String.Format("Error creating controller {0}" + controllerType);  
  29.         throw new InvalidOperationException(message, ex);  
  30.     }  
  31. }  
  32.  

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

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

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

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

【編輯推薦】

  1. ASP.NET Routing之“解析URL”功能詳解
  2. 為ASP.NET MVC應用添加自定義路由
  3. 學習ASP.NET MVC路由的使用方法
  4. 淺析ASP.NET中的URL Rewrite
  5. 淺談ASP.NET MVC框架
責任編輯:yangsai 來源: 老趙點滴
相關推薦

2015-02-12 15:33:43

微信SDK

2015-02-12 15:38:26

微信SDK

2017-08-22 16:40:22

前端JavaScript接口

2009-09-07 22:00:15

LINQ自定義

2022-05-18 07:44:13

自定義菜單前端

2024-04-03 09:18:03

Redis數據結構接口防刷

2024-08-26 11:13:26

字典entry自定義

2009-07-06 17:36:06

ResultSetJDBC Connec

2009-06-17 16:00:03

Hibernate自定

2009-09-03 13:34:03

.NET自定義控件

2013-01-09 17:22:38

Android開發Camera

2022-03-01 16:09:06

OpenHarmon鴻蒙單選組件

2015-07-29 10:31:16

Java緩存算法

2022-12-07 08:56:27

SpringMVC核心組件

2022-04-01 15:59:22

SQLPostgreSQL審計

2023-01-03 07:40:27

自定義滑塊組件

2023-10-24 13:48:50

自定義注解舉值驗證

2009-07-06 16:20:50

JSP自定義標簽

2011-05-27 09:51:44

Windows Pho應用商店

2021-02-20 11:40:35

SpringBoot占位符開發技術
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 先锋资源网 | 国产欧美日韩在线一区 | 99久久国产精| 色永久 | 在线视频 欧美日韩 | 色一情一乱一伦一区二区三区 | 91视频免费黄 | 欧美日韩综合视频 | 亚洲欧美日本在线 | 国产三级国产精品 | 国内精品久久久久久久影视简单 | aaa国产大片| 亚洲精品第一国产综合野 | 亚洲超碰在线观看 | 欧美国产视频 | 黑人精品 | 亚洲乱码国产乱码精品精的特点 | 精品国产91乱码一区二区三区 | 国产精品久久久 | 精品综合久久 | 成人在线免费看 | 成人在线免费 | 一区二区三区视频在线 | 99在线免费观看视频 | 情侣酒店偷拍一区二区在线播放 | 中文字幕电影在线观看 | 婷婷综合网 | 福利在线看 | 欧美午夜精品 | 国产乱码精品一品二品 | 北条麻妃99精品青青久久主播 | 妖精视频一区二区三区 | 国产蜜臀| 国产91综合 | 欧美日韩亚洲在线 | 91一区二区三区 | 欧美一区二区三区在线观看视频 | 欧美极品在线视频 | 欧美国产一区二区 | 99久久婷婷国产综合精品电影 | 日韩视频精品在线 |