日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程)

發布時間:2024/1/17 asp.net 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

閱讀目錄:

  • 1.開篇介紹
  • 2.ASP.NETMVC IControllerFactory 控制器工廠接口
  • 3.ASP.NETMVC DefaultControllerFactory 默認控制器工廠
  • 4.ASP.NETMVC ControllerBuilder 控制器創建入口設置
  • 5.ASP.NETMVC 自定義IControllerFactory

1】開篇介紹

上一篇文章“.NET/ASP.NET MVC Controller 控制器(一:深入解析控制器運行原理)”詳細的講解了MvcHandler對象內部的基本流程邏輯,這基本的流程邏輯為我們后面的學習起到鋪墊作用,當我們能正確的搞懂它的內部執行流程后,我們就可以順藤摸瓜的去挖掘每個邏輯環節中的詳細邏輯;

通過前面兩篇文章的介紹,我們基本上能搞清楚一個Url請求是如何借助于UrlRoutingModule模塊順利穿過ASP.NET基礎框架到達應用框架的過程,當UrlRoutingModule處理過后將RouteData對象封裝在RequestContext請求上下文中傳入到MvcHandler對象,然后MvcHandler對象通過IControllerFactory接口根據從RouteData中獲取到controllername控制器名稱字符串創建具體的IController對象實例;

這基本的流程我們是清晰了,但是我們并不太清楚IControllerFactory背后所發生的一切,到底誰作為IControllerFactory默認實現的,它又有著怎樣的擴展入口讓我們來擴展創建過程,這值得一探究竟;

那么這篇文章讓我們來分析一下IControllerFactory的背后所發生的事情,我們是否能從中學到什么設計思想;

2】ASP.NETMVC IControllerFactory 控制器工廠接口

既然能將ControllerFactory提取出接口來,那么對于IController的創建將是一個非常寬松的過程;簡單的設想一下,如果不將Factory提出接口來,那么對于IController的創建將是一個很直觀的過程,但是ASP.NETMVC將IController創建不是簡單的使用一個ControllerFactory來解決,而是將這個創建過程設計的很松散,目的是為了擴展性方便,換句話說我們完全可以自定義一個Factroy來替代這個創建過程,也可以基于系統內部的Factroy來擴展一下;

MvcHandler使用IControllerFactroy創建出相應IController對象,那么首先我們需要搞清楚MvcHandler通過什么方式獲取到實現IControllerFactory接口的;

其實在MvcHandler中并不是直接使用IControllerFactroy的相關實現,而是使用了ControllerBuilder對象,這個對象是一個單例模式的實現;MvcHanlder通過ControllerBuilder對象獲取到一個實例,然后通過ControllerBuilder創建出IControllerFactory實現;

1 internal ControllerBuilder ControllerBuilder { 2 get { 3 if (_controllerBuilder == null) { 4 _controllerBuilder = ControllerBuilder.Current; 5 } 6 return _controllerBuilder; 7 } 8 set { 9 _controllerBuilder = value; 10 } 11 } 12 13 factory = ControllerBuilder.GetControllerFactory();

可以簡單的理解為,ControllerBuilder管理著IControllerFactory的創建過程,MvcHanlder通過獲取ControllerBuilder的全局實例,然后調用其方法GetControllerFactory,得到可以使用的IControllerFactory實現;

圖1:

ControllerBuilder的設計很巧妙,它將IControllerFactory的實現為我們敞開了大門,我們可以通過這個入口做很多事情;

我們看一下IControllerFactroy接口的定義:

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

接口中定義了三個方法,第一個方法CreateController很好理解,根據方法的第二個參數controllerName創建Controller實例;第二個方法GetControllerSessionBehavior方法是用來獲取controllerName所代表的Controller的Session行為的,該行為是通過SessionStateAttribute特性表示;第三個方法ReleaseController方法是用在最后釋放Controller的:

1 public virtual void ReleaseController(IController controller) { 2 IDisposable disposable = controller as IDisposable; 3 if (disposable != null) { 4 disposable.Dispose(); 5 } 6 }

由于Controller繼承自IDisposable接口,所以在方法內部是直接調用Dispose方法來釋放資源;這里需要注意的是,Controller對IDisposable接口的實現是virtual修飾符:

1 protected virtual void Dispose(bool disposing) { 2 }

這就很方便我們通過重寫此方法的方式來釋放一些其他資源;

3】ASP.NETMVC DefaultControllerFactory 默認控制器工廠

在ASP.NETMVC內部有一個默認的Factroy(DefaultControllerFactroy),DefaultControllerFactroy實現了核心的創建IController代碼,這為我們的擴展提供了很好的接口;

通過調用IControllerFactory接口的CreateController(RequestContext requestContext, string controllerName) 方法,將進入到DefaultControllerFactory實現中,首要任務就是要根據controllerName名稱找到對應的ContorllerType,然后才能創建具體的實例;

1 object routeNamespacesObj; 2 Type match; 3 if (requestContext != null && requestContext.RouteData.DataTokens.TryGetValue("Namespaces", out routeNamespacesObj)) { 4 IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>; 5 if (routeNamespaces != null && routeNamespaces.Any()) { 6 HashSet<string> nsHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase); 7 match = GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, nsHash); 8 9 // the UseNamespaceFallback key might not exist, in which case its value is implicitly "true" 10 if (match != null || false.Equals(requestContext.RouteData.DataTokens["UseNamespaceFallback"])) { 11 // got a match or the route requested we stop looking 12 return match; 13 } 14 } 15 }

首先根據請求的路由數據RouteData,查找設置的命名空間集合,然后使用命名空間和控制器名稱獲取Type,如果Type!=null并且沒有開啟后被命名空間則直接返回Type;

3.1】Controller中的AreaRegistration命名空間

在DefaultControllerFactroy內部使用到了兩組命名空間來作為查找Controller的NameSpace,第一個是我們在配置Route數據的時候設置的:

1 context.MapRoute(name: "api.order.default", url: "api/order/{controller}/{action}/{orderid}", 2 defaults: new { controller = "OrderController", action = "GetOrderOperationDatetime", orderid = "1001" }, 3 namespaces: new string[] { "Api.Order" });

而第二個我們一般都不會用它的,它是作為AreaRegistration后備命名空間而存在的,是在ControllerBuilder中設置的:

1 ControllerBuilder.Current.DefaultNamespaces.Add("MvcApplication4.ApiOrder");

對后備命名空間的賦值是在AreaRegistrationContext中的MapRoute(string name, string url, object defaults, object constraints, string[] namespaces) 方法中完成的:

1 if (namespaces == null && Namespaces != null) { 2 namespaces = Namespaces.ToArray(); 3 }

?

1 Route route = Routes.MapRoute(name, url, defaults, constraints, namespaces); 2 route.DataTokens["area"] = AreaName; 3 4 // disabling the namespace lookup fallback mechanism keeps this areas from accidentally picking up 5 // controllers belonging to other areas 6 bool useNamespaceFallback = (namespaces == null || namespaces.Length == 0); 7 route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback; 8 9 return route;

由于AreaRegistration可以讓我們對Controller的設計不局限于ASP.NETMVCWeb程序中,而可以將Controller獨立出去進行模塊化設計,所以需要提供有關Area的特殊命名空間查找方式;

4】ASP.NETMVC ControllerBuilder 控制器創建入口設置

ControllerBuilder作為Controller創建的設置入口,可以用來設置ControllerFactory替換系統默認的DefaultControllerFactory,ControllerBuilder是Controller的創建過程框架擴展入口,可以借助ControllerBuilder方便做很多設置;

1 internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver) { 2 _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>( 3 () => _factoryThunk(), 4 new DefaultControllerFactory { ControllerBuilder = this }, 5 "ControllerBuilder.GetControllerFactory" 6 ); 7 }

在ControllerBuilder的構造函數中,初始化了一個SingleServiceResolver<IControllerFactory>類型的Resolver,目的是為了對Factory實現IOC方式的獲取;在代碼中,實例化了一個DefaultControllerFactory類型的實例作為默認的Factory,比較重要的是將ControllerBuilder做為參數設置到了ControllerBuilder屬性中,目的是為了能在后面解析Controller命名空間的時候用到;

1 public HashSet<string> DefaultNamespaces { 2 get { 3 return _namespaces; 4 } 5 }

在此我們可以設置統一的命名空間,由于我們在設置Route的時候,都需要設置namesapce字段,但是如果有很多這樣的Route的時候就很麻煩,我們可以通過此方式進行統一的設置;

1 public void SetControllerFactory(IControllerFactory controllerFactory) { 2 if (controllerFactory == null) { 3 throw new ArgumentNullException("controllerFactory"); 4 } 5 6 _factoryThunk = () => controllerFactory; 7 }

還有一個比較重要的就是設置自定義的ControllerFactory,在方法SetControllerFactory中,我們可以設置一個IControllerFactory類型的對象,就可以接管系統默認的DefaultControllerFactory對象,包括后面的所有的IController緩存策略;

圖2:

基本上我們可以通過ControllerBuilder進入到ControllerFactroy的創建環節來,使用SetControllerFactory方法直接將我們自定義的IControllerFactroy傳入即可;

5】ASP.NETMVC 自定義IControllerFactory

既然知道了ContollerBulder可以使我們更改系統默認的控制器工廠,那么我們通過怎樣的方式使用現在的Factroy;大致上我們只需要繼承自DefaultControllerFactory然后進行相應的擴展即可;

1 public class CustomControllerFactory : DefaultControllerFactory 2 { 3 protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) 4 { 5 Console.WriteLine(string.Format("{0}is create.", controllerType.Name)); 6 return base.GetControllerInstance(requestContext, controllerType); 7 } 8 }

現在假設我們需要在系統創建所有Controller的時候能記錄下創建的記錄信息,這樣就很方便的完成了,我們只需要在系統初始化的地方進行設置:

1 ControllerBuilder.Current.SetControllerFactory(new Api.Order.CustomControllerFactory());

這樣我們就接管了ControllerFactory的部分功能;

?

作者:王清培

出處:http://www.cnblogs.com/wangiqngpei557/

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。

總結

以上是生活随笔為你收集整理的.NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。