說明ASP.NET MVC Http請求是如何到達控制器操作的!!!

来源:http://www.cnblogs.com/Lxy-/archive/2016/08/16/5774844.html
-Advertisement-
Play Games

1 引言 小弟在學習技術的時候有個毛病,往往喜歡先吃下一大桶理論然後再去實踐,不僅要知道這個 如何去做 還想知道 為什麼可以這麼做? ,但是事實是在工作時候項目經理可沒有興趣讓你去研究這些,特別是在小弟現在的公司是外包的情況下差點被辭退(這裡就不詳說了...) 顯然我也知道這樣不對,因為公司請你是來 ...


1 引言


 

      小弟在學習技術的時候有個毛病,往往喜歡先吃下一大桶理論然後再去實踐,不僅要知道這個 如何去做 還想知道 為什麼可以這麼做? ,但是事實是在工作時候項目經理可沒有興趣讓你去研究這些,特別是在小弟現在的公司是外包的情況下差點被辭退(這裡就不詳說了...) 顯然我也知道這樣不對,因為公司請你是來快速完成任務的而不是讓你研究的!但是小弟依舊沒完全改掉這個毛病!或許說不知道工作和學習正常的分配吧!正因為這個毛病所以寫了這篇博客,還望和各位bigGod共同學習吧!!

 

2 進入正題


 

      在進入正題前小弟希望閱讀者能瞭解最基本ASP.NET MVC 路由模板 ,小弟不會從伺服器(如:IIS)最低層的請求如何到達你的WebApplication進程進行說明,這個網上資料有很多如果想瞭解推薦http://www.cnblogs.com/lumnm/archive/2009/08/08/1541901.html這篇清晰易懂。這裡只講解ASP.NET MVC管道的http請求如何到達控制器操作。

  • 創建實例

      在說明之前首先我們創建一個預設的MVC項目(相信大家都會創建,這裡就不演示了),打開根目錄下\Global.asax.cs文件

在此文件下項目自動生成了一些代碼如下:

 

 1  public class MvcApplication : System.Web.HttpApplication
 2     {
 3         protected void Application_Start()
 4         {
 5             AreaRegistration.RegisterAllAreas(); //配置區域路由 目的在大型複雜網站下方便管理路由
 6             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  //配置過濾特性
 7             RouteConfig.RegisterRoutes(RouteTable.Routes);  //配置傳統路由
 8             BundleConfig.RegisterBundles(BundleTable.Bundles); //配置捆綁縮減的JS和css文件
 9 
10         }
11 
12     }
 

   上面代碼中MVCApplication類的Application_Start()是整個程式的入口,在這裡可以配置整個web程式的全局屬性,而且我們的MvcApplication 繼承至HttpApplication,伺服器(如IIS)的請求都要經過HttpApplication的處理管道,管道內的處理過程是固定的,在伺服器處理請求的各個階段,依次觸發對應的事件,便於程式員在不同的階段完成自定義的處理工作。查看HttpApplication的元數據(滑鼠右鍵轉到定義)發現有24個事件,但是我們一般關心是如下19個管道事件:

(註:圖片轉至 木宛城主的博客:http://www.cnblogs.com/OceanEyes/p/thinking-in-asp-net-mvc-apply-asp-net-identity-authentication.html)

 

 

      在MVC里處理請求的是UrlRoutingModule類,它是一個實現了IHttpModule介面的類,那這個介面的作用是什麼呢?只要繼承至IHttpModule介面的類就可以訂閱HttpApplication生命周期的各個事件。下麵是IHttpModule介面的代碼:(非常簡單)

 

1  public interface IHttpModule
2  {
3       void Dispose();
4       void Init(HttpApplication context);
5  }

 

    Init方法是實現HttpModule功能的主要方法,它有一個HttpApplication類型的context參數,這個參數允許訪問當前HttpApplication的環境以此來訂閱註冊處理請求過程中不同的事件,為了更好的理解UrlRoutingModule類的運行機制,我寫個小例子,該例修改http輸出流,在每個輸出流加上請求時間和請求處理完畢時間。在你自己隨意位置(如:/Models或重新創建一個類庫項目)下添加一個類,然後讓它繼承IHttpModule介面並實現。代碼如下:

 1  public class MyModule : IHttpModule
 2     {
 3 
 4         private HttpApplication _application = null;
 5 
 6         public void Init(HttpApplication context)
 7         {
 8 
 9             _application = context;
10 
11             string reqTime = string.Empty; //請求時間
12             string resTime = string.Empty; //請求完畢時間
13 
14             // //通過訂閱HttpApplication的BeginRequest事件,這個事件在收到一個http請求時發生
15             _application.BeginRequest += (obj, e) =>
16             {
17                reqTime = string.Format("請求時間:{0}", DateTime.Now.ToString());
18             };
19 
20             //通過訂閱HttpApplication的EndRequest事件,這個事件會在把響應內容發送給客戶端前觸發
21             _application.EndRequest += (obj, e) =>
22             {
23                 resTime = string.Format("請求處理後時間:{0}", DateTime.Now.ToString());
24 
25                  _appliction.Context.Response.Write(reqTime+"<br/>"+resTime); //在每個響應內容流里寫入當前請求的時間
26 
27             };
28         }
29     }

      為了使用這個模塊,我們要在請求處理管道上包含該模塊。為此我們配置web.config文件使其包含它一個引用。在web.config文件的<httpModules>節點下添加:

      <add name="ClassName" type="NameSpace.ClassName,AssemblyName" />

      我的例子ClassName是MyModule,命名空間是MvcDemo.Models,所以我的節點如下

 <httpModules>

       <add name="MyModule" type="MvcDemo.Models.MyMoule,MvcDemo" />

 </httpModules>

      

然後按F5運行你就會發現每個頁面多了2排分別表示請求和請求完畢的時間的文字

 

    現在你應該大概瞭解UrlRoutingModule類的功能了,路由機制就是利用這個原理,它通過註冊HttpApplication事件參與到管道處理請求中,具體是訂閱HttpApplication某個階段的事件。UrlRoutingModule訂閱了PostResolveRequestCache 事件,實現url的映射。為什麼是該事件呢?因為該事件的下一步就要完成請求和物理文件的映射,所以必須要此之前進行攔截。

細心的朋友可能發現在 <httpModules>節點下並沒有添加 UrlRoutingModule類的引用啊,其實web.config配置可以分為本站和全局,全局的配置在C:\Windows\Microsoft.NET\Framework\v版本號\Config\web.config文件里

 

 

 在瞭解了UrlRoutingModule類的功能下,我們繼續查看它如何映射到控制器操作的,核心源代碼如下:

 

public class UrlRoutingModule : IHttpModule
    {
        protected virtual void Init(HttpApplication application)
        {
            if (application.Context.Items[_contextKey] == null)
            {
                application.Context.Items[_contextKey] = _contextKey;
//註冊訂閱HttpApplication對象的PostResolveRequestCache事件 application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);//事件觸發時會執行下麵的方法 } } private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) { HttpContextBase context = new HttpContextWrapper(((HttpApplication)sender).Context); this.PostResolveRequestCache(context); } }

     

      從源碼看出UrlRoutingModule其實跟我們上面那例子差不多都是通過註冊事件來執行相應的代碼功能的。

在瞭解更多源碼之前,我們先來瞭解下路由的基本知識,路由其實並非是ASP.NET MVC的一個特性,其實它僅在MVC1.0的前期階段是MVC獨有的,但是後面ASP.NET團隊把它變成了獨立的項目,所以它並不依賴於MVC,這是個題外話。我們現在要做的是依然打開根目錄下\Global.asax.cs文件

 public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
         
//這裡就是我們配置路由的代碼方法 RouteConfig.RegisterRoutes(RouteTable.Routes);
//配置傳統路由 } }


//方法的代碼在/App_Start文件目錄下的RouteConfig.cs文件
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.MapMvcAttributeRoutes(); //開啟特性理由 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");//忽略映射文件 routes.MapRoute( name: "Default1", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); routes.MapRoute( name: "Default2", url: "Side/{Year}/{Month}/{Day}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }

 

 這裡的路由知識我不說明,因為我相信閱讀者都能看懂上面的代碼,它就是添加了2個傳統路由的路由模板,我們關註的對象是傳進給RegisterRoutes方法的RouteTable.Routes參數,RouteTable其實就是一個封裝成全局對象的路由集合源代碼如下(非常簡單)

 public class RouteTable
    {
        private static RouteCollection _instance = new RouteCollection();
        
        public static RouteCollection Routes =>
            _instance;
    }

 

 可以看見RouteTable.Routes參數其實就是一個全局的RouteCollection對象,這樣你的路由集合保證了全局唯一性,調用也方便。通過RouteCollection集合對象我們可以通過它的Add添加Reute對象。

 1  routes.MapRoute(
 2                 name: "Default1",
 3                 url: "{controller}/{action}/{id}",
 4                 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
 5             );
 6 
 7 
 8  public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
 9         {
10   
11             Route route = new Route(url, new MvcRouteHandler()) {
12                 Defaults = CreateRouteValueDictionaryUncached(defaults),
13                 Constraints = CreateRouteValueDictionaryUncached(constraints),
14                 DataTokens = new RouteValueDictionary()
15             };
16 ConstraintValidation.Validate(route); 17 if ((namespaces != null) && (namespaces.Length > 0)) 18 {
19 route.DataTokens["Namespaces"] = namespaces; 20 } 21 routes.Add(name, route); 22 return route; 23 }

 

可以從源代碼看出實踐RouteCollection集合對象的MapRoute方法也是調用的Add方法添加的路由模板。

---------------------------------------------------------------------------------未完待續--------------------------------------------------------------------------------------------------------------

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 結合實際的工作環境,在開始R研究的時候,首先著手收集的就是能以Web方式發佈R運行結果的基礎框架,無耐的是,R一直以來常使用於個人電腦的客戶端程式上,大家習慣性的下載R安裝包,在自己的電腦上安裝 --> 寫演算法 --> 運行 --> 以貼圖或者文檔的形式發表自己的作品。花了較長時間,終於找著了一套框 ...
  • 《SQL 必知必會》讀書筆記 -- 第9課 彙總數據 9.1 聚集函數:對某些行運行的函數,計算並返回一個值 案例: -- 確定表中函數 -- 獲得表中某些行的和 -- 找出表列的最大值、最小值和平均值等 --當我們實際想要彙總信息,而不是需要數據本身時,可節省時間和帶寬。 --表9-1 --函數 ...
  • 【BBED】bbed常用命令 一.1 相關知識點掃盲 BBED(Oracle Block Browerand EDitor Tool),用來直接查看和修改數據文件數據的一個工具,是Oracle一款內部工具,可以直接修改Oracle數據文件塊的內容,在一些極端恢復場景下比較有用。該工具不受Oracle... ...
  • R 是一門擁有統計分析及作圖功能的免費軟體,主要用於數學建模、統計計算、數據處理、可視化等方向。據 IEEE Spectrum發佈的2016年編程語言前10位排名來看,R語言由2015年排名第6位上升級2016年的第5位。目前在CRAN 上發佈的演算法包已經超過8000+多個。R體系涉及到高等數據、概 ...
  • IMAGE_SECTION_HEADER 的源代碼如下: 每個區塊表長度占40個位元組。 * 表示需要註意的欄位,最有用的是 SizeOfRawData 、 PointerToRawData 和Characteristics 欄位。 Name * 此欄位時區塊名。(一句話:名字而已,沒什麼用) 要求: ...
  • 這篇主要是記錄Linux下安裝Node及memcached遇到的問題及安裝配置過程,方便日後查閱 Node安裝及配置 安裝完後需要配置Node的環境變數 檢查是否安裝成功 一切正常,完成安裝 memcached安裝配置 由於memcached的執行需要依賴於libevent,先安裝libevent( ...
  • root用戶下,操作以下5步: 1、查網路,保證本機與對方互相通信 ifconfig ipconfig ping 2、查Linux的對應服務是否啟動,使服務的status保持running狀態 比如ssh: /etc/init.d/sshd status /etc/init.d/sshd resta ...
  • 電腦系統有一系列的“周期”概念,區別、聯繫地理解這些概念至關重要。以下對時鐘周期、振蕩周期、機器周期、CPU周期、狀態周期、指令周期、匯流排周期、任務周期進行簡單介紹。 電腦系統有一系列的“周期”概念,區別、聯繫地理解這些概念至關重要。以下對時鐘周期、振蕩周期、機器周期、CPU周期、狀態周期、指令 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...