c# mvc框架原理

目錄:

一、MVC原理解析

二、HttpHandler

       1.HttpHandler,IHttpHandler,MvcHandler的說明

       2.IHttpHandler解析

       3.MvcHandler解析

三、HttpModule

       1.HttpModule能幹什麼

       2.HttpModule的使用

       3.HttpModyle和HttpHandler如何區分

       4.UrlRoutingModule解析

一、MVC原理解析

當我們收到一個URL的請求是,服務端收到請求,主要經歷以下幾個步驟:

1.請求被UrlRoutingModule部件攔截

2.封裝請求上下文HttpContext,成爲HttpContextWrapper對象

3.根據當前的HttpContext,從Routes集合中得到與當前請求URL相符合的RouteData對象

4.將RouteData與HttpContext請求封裝成一個RequestContext對象

5.根據RequestContext對象,從RouteData的RouteHandler中獲取IHttpHandler(MVC裏面會有一個IHttpHandler的實現類MvcHandler)。

6.執行IHttpHandler(MVCHandler),然後就是通過反射激活具體的controller,執行具體的action。

1.整個過程有兩個核心的組件。UrlRoutingModule和MvcHandler,上文提到的各個過程都和兩個組件有緊密的聯繫。而這兩個組件分別繼承Ihhtmodule和IhttpHandler接口,熟悉Asp.Net管線事件的朋友應該記得這兩個接口。

2.UrlRoutingModule的作用可以理解爲通過一系列的與路由相關的組件去解析當前請求的Controller與Action名稱,其實簡單點理解,比如我們請求的http://localhost:8080/Home/Index這個url的時候,UrlRoutingModule攔截到這個請求,然後通過一系列的方式得到這裏的“Home"和”Index"

3.MvcHandler的作用就更加直接,上述通過攔截組件得到了請求的Controller和Action的名稱,MvcHandler組件將當前請求的Controller名稱反射得到對應的控制器對象,然後執行對應的Action方法。比如還是上述http:/localhost:8080/Home/Index這個請求,通過字符串“Home”反射成爲Home這個類型的控制器對象,然後調用這個對象的Index()方法。

4.綜上,聯合這兩個組件來理解,UrlRoutingModule組件的主要作用是解析當前的Controller與Action名稱,MvcHandler的作用是將得到Controller名稱激活,得到具體的Controller對象,然後執行對應的Action方法。

 二、HttpHandler

HttpHandler指所有實現IHttpHandler接口一類類型的統稱,他是一個大的稱謂。這些類型有一個共同的功能,那就可以用來處理http請求。

IHttpHandler是微軟定義的一類接口,用來約束所有能夠處理的http的類型的接口規則

MVcHandler是MVc裏面實現IHttpHandler接口的類型,也就是說,MvcHandler是Mvc裏面處理Http請求的類型。

總而言之,HttpHandler只是一個邏輯稱謂,它並不存在,而IhhtpHandler和MvcHandler是.net framework裏面具體存在的接口和實現類,是前者的表現形式。

IHttpHandler解析

做過webform開發的應該直到,在asp.net的頁面生命週期裏面,一共有24個管線事件,完整的管線使勁按可參考msdn文檔:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

在處理該請求時將由 HttpApplication 類執行以下事件。 希望擴展 HttpApplication 類的開發人員尤其需要注意這些事件。

1. 對請求進行驗證,將檢查瀏覽器發送的信息,並確定其是否包含潛在惡意標記。 有關更多信息,請參見 ValidateRequest 和腳本侵入概述。

2. 如果已在 Web.config 文件的 UrlMappingsSection 節中配置了任何 URL,則執行 URL 映射。

3. 引發 BeginRequest 事件。

4. 引發 AuthenticateRequest 事件。

5. 引發 PostAuthenticateRequest 事件。

6. 引發 AuthorizeRequest 事件。

7. 引發 PostAuthorizeRequest 事件。

8. 引發 ResolveRequestCache 事件。

9. 引發 PostResolveRequestCache 事件。

10. 根據所請求資源的文件擴展名(在應用程序的配置文件中映射),選擇實現 IHttpHandler 的類,對請求進行處理。 如果該請求針對從 Page 類派生的對象(頁),並且需要對該頁進行編譯,則 ASP.NET 會在創建該頁的實例之前對其進行編譯。

11. 引發 PostMapRequestHandler 事件。

12. 引發 AcquireRequestState 事件。

13. 引發 PostAcquireRequestState 事件。

14. 引發 PreRequestHandlerExecute 事件。

15. 爲該請求調用合適的 IHttpHandler 類的 ProcessRequest 方法(或異步版 IHttpAsyncHandler.BeginProcessRequest)。 例如,如果該請求針對某頁,則當前的頁實例將處理該請求。

16. 引發 PostRequestHandlerExecute 事件。

17. 引發 ReleaseRequestState 事件。

18. 引發 PostReleaseRequestState 事件。

19. 如果定義了 Filter 屬性,則執行響應篩選。

20. 引發 UpdateRequestCache 事件。

21. 引發 PostUpdateRequestCache 事件。

22. 引發 EndRequest 事件。

23. 引發 PreSendRequestHeaders 事件。

24. 引發 PreSendRequestContent 事件。

 

Asp.net管線事件說明

  在整個管線事件中,有兩個重要的角色就是HttpHandler和HttpModule。

Asp.net 中常見的httphandler類型

1

2

3

4

5

6

7

8

public interface IHttpHandler

{

    // 定義一個處理當前http請求的方法

    void ProcessRequest(HttpContext context);

 

    // 指示當前實例是否可以再次使用

    bool IsReusable { get; }

}

  

接口的定義很簡單,ProcessRequest()方法裏面傳一個當前請求的上下文對象去處理當前的http請求

爲了處理異步請求,framework裏面還定義了一個異步的IHttpHandler接口:

1

2

3

4

5

6

public interface IHttpAsyncHandler : IHttpHandler

{

    // Methods

    IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);

    void EndProcessRequest(IAsyncResult result);

}

  

接口的兩個方法應該也不難理解。

HttpHandler的主要作用是處理http請求,一般處理程序還記得嗎,ashx。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

public class DemoHandler : IHttpHandler

    {

 

        public void ProcessRequest(HttpContext context)

        {

            context.Response.ContentType = "text/plain";

 

            var username = context.Request.QueryString["username"];

            var password = context.Request.QueryString["password"];

            if (username == "admin" && password == "admin")

            {

                context.Response.Write("用戶admin登錄成功");

            }

            else

            {

                context.Response.Write("用戶名或者密碼錯誤");

            }

        }

 

        public bool IsReusable

        {

            get

            {

                return false;

            }

        }

    }

  

然後運行,通過http://localhost:8080/DemoHandler.ashx?username=admin&password=admin去訪問一般處理程序,既可以得到正確的結果。

當然,除了這個,我們還有最常見的aspx頁面

1

2

3

4

5

6

7

public partial class TestPage : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

 

        }

    }

  

將page類轉到定義

發現原來page類也是繼承ihttphandler,這就是爲什麼可以用地址http://localhost:8080/TestPage.aspx來訪問這個頁面的原因。當然,子類中的ProcessRequest()方法並沒有顯示的聲明出來,因爲在page類裏面有一個virtual的虛方法,當然,你也可以顯示的聲明出來。

1

2

3

4

5

6

7

8

9

10

11

12

public partial class TestPage : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

 

        }

 

        public void ProcessRequest(HttpContext context)

        {

            context.Response.Write("你好");

        }

    }<br><br>

然後再運行你會發現這個時候請求會進到ProcessRequest()方法,而不會進入到Page_Load()裏面了,至於原因,這和Page類裏面的封裝有關係。當然這不是本文的重點,本文要說明的是所有實現了IHttpHandler接口的類型都可以再ProcessRequest()方法黎曼處理當前的http請求。

當然,除了ashx和aspx之外,還有一類http的服務接口處理文件asmx也和IHttpHandler有着不可分割的聯繫,可以說,再asp.net裏面,只要是處理http請求的地方,IhttpHandler幾乎“無處不在"

當然,除了上述asp.net自帶的HttpHandler之外,我們也可以自定義HttpHandler處理待定的請求。比如我們新建一個Demo.cs頁面

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class DemoHandler:IHttpHandler

    {

        public bool IsReusable

        {

            get return false; }

        }

 

        public void ProcessRequest(HttpContext context)

        {

            context.Response.Write("從asex頁面進來");

 

            //throw new NotImplementedException();

        }

    }

 

當然,要使用這個自定義的handler需要在web.config裏面加上配置。

1

2

3

4

5

<system.webServer>

   <handlers>

        <add name="asex" verb="*" path="*.asex" type="MyTestMVC.DemoHandler, MyTestMVC" preCondition="integratedMode" />

    </handlers>

</system.webServer>

 這個配置的意思就是所有的url一asex結尾的請求都交給DemoHandler這個類去處理

localhost:8080/DemoHandel.asex

頁面就會顯示內容

MvcHandler解析

上文介紹了那麼多的KHttpHandler的用法,都是webform裏面的一些實現,我們知道了所有實現了IHttpHandler的類都可以處理Http請求。同樣在MVC裏面。也定義了一個實現IhttpHandler接口的類型,MvcHandler,用於處理當前http請求。通過反編譯工具可以看到:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState

{

    // 省略若干字段// 所有方法

    static MvcHandler();

    public MvcHandler(RequestContext requestContext);

    protected internal virtual void AddVersionHeader(HttpContextBase httpContext);

    protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state);

    protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state);

    protected internal virtual void EndProcessRequest(IAsyncResult asyncResult);

    private static string GetMvcVersionString();

    protected virtual void ProcessRequest(HttpContext httpContext);

    protected internal virtual void ProcessRequest(HttpContextBase httpContext);

    private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory);

    private void RemoveOptionalRoutingParameters();

    IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);

    void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result);

    void IHttpHandler.ProcessRequest(HttpContext httpContext);

 

    // 省略若干屬性

} 

MvcHandler實現了IHttpHandler,IHttpAsynHandler兩個接口,異步請求這裏先不做介紹。重點還是來看看ProcessRequest()方法

將HttpContext轉換爲HttpContextBase對象,繼續轉到定義

這裏聲明瞭一個IController和IControllerFactory對象,通過this.ProcessRequestInit()方法創建具體的Controller實例。我們將ProcessRequestInit()方法轉到定義

 

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)

        {

            //1.得到當前的上下文

            HttpContext current = HttpContext.Current;

            if (current != null && ValidationUtility.IsValidationEnabled(current) == true) ValidationUtility.EnableDynamicValidation(current);

            this.AddVersionHeader(httpContext);

            this.RemoveOptionalRoutingParameters();

 

            //2.從路由對象RouteData中獲取當前請求的Controller名稱

            string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");

 

            //3.得到Controller工廠對象

            factory = this.ControllerBuilder.GetControllerFactory();

 

            //4.根據當前RequestContext對象,從Controller工廠創建具體的Controller對象

            controller = factory.CreateController(this.RequestContext, requiredString);

            if (controller == nullthrow new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[] { factory.GetType(), requiredString }));

        }  

 通過上文的註釋可以很好理解整個控制器的實例化過程。本打算看下Controller工廠如何創建以及控制器如何實例化,奈何部分反編譯不了。我們暫且理解爲反射吧。這些細節並不影響我們理解整個過程。

創建控制器成功之後,就是執行Action方法了,這個過程在上面反編譯的第二張圖片的controller.Execute(this.RequestContext);方法得到體現。所以,除去細節,理解mvchandler的ProcessRequest()方法並不是太難。

三、HttpModule

除了HttpHandler之外,asp.net裏面還有另外一個重要的角色--HttpModule。和HttpHandler類似,HttpModule指所有實現了IhttpModule接口的一類類型的統稱。至於HttpModule,IHttpModule,UroroutingModule各個名臣的含義和上述HttpHandler相同,在此不做重複說明。

1.httpmodule能幹什麼,通過上文,我們直到httphandler的作用非常明確:處理http請求,生成相應的結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章