透過MvcRouteHandler取得呼叫IHttphandler (第10天)

Agenda

前言

前一篇介紹路由封裝了Http請求路徑資訊可以讓我們找到相對應的ActionController並呼叫執行外,也可透過MapPageRoute來將請求教給.aspx實體檔案來處理請求.

Route甚至可以讓我們自己客製化處理HttpHandler 在Route中建立處理客製化HttpHandler可謂很有彈性

本篇介紹Route物件建立MvcRouteHandler物件且如何取到IHttpHandler.

我有做一個可以針對於Asp.net MVC Debugger的專案,只要下中斷點就可輕易進入Asp.net MVC原始碼.

MVC取得使用HttpHandler (IHttpHandler)

之前說到我們透過MapRoute擴展方法加入一個Route物件給RouteCollection全域路由集合.

Route使用的IRouteHandler介面是由MvcRouteHandler來實現

1
2
3
4
5
6
Route route = new Route(url, new MvcRouteHandler())
{
Defaults = CreateRouteValueDictionaryUncached(defaults),
Constraints = CreateRouteValueDictionaryUncached(constraints),
DataTokens = new RouteValueDictionary()
};

IRouteHandler最重要的是IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)會取得一個IHttpHandler物件.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class MvcRouteHandler : IRouteHandler
{
private IControllerFactory _controllerFactory;

public MvcRouteHandler()
{
}

public MvcRouteHandler(IControllerFactory controllerFactory)
{
_controllerFactory = controllerFactory;
}

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
//設置Session使用
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}

protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
{
string controllerName = (string)requestContext.RouteData.Values["controller"];
if (String.IsNullOrWhiteSpace(controllerName))
{
throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController);
}

IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
}

#region IRouteHandler Members

IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return GetHttpHandler(requestContext);
}

#endregion
}

上面程式碼可以看到Mvc使用IHttpHandlerMvcHandler

MVC呼叫的HttpHandler (MvcHandler)

MvcHandler類別中主要核心的程式碼做了幾件事情.

  1. 使用一個Adapter對於HttpContext物件把他轉成可以繼承於HttpContextBaseHttpContextWrapper類別.
  2. 透過ProcessRequestInit取得執行controller物件並且呼叫執行方法.
  3. 最後透過ReleaseController釋放之前使用過資源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected virtual void ProcessRequest(HttpContext httpContext)
{
HttpContextBase httpContextBase = new HttpContextWrapper(httpContext);
ProcessRequest(httpContextBase);
}

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory;
//取得 控制器工廠(預設DefaultControllerFactory) 和 要執行的Controller
ProcessRequestInit(httpContext, out controller, out factory);

try
{
controller.Execute(RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
}

小結

今天我們知道MVC使用HttpHandlerMvcHandler透過並MvcRouteHandler物件來返回.

下圖簡單展現MVC使用的HttpModuleHttpHandler關係

relationship_pic.PNG

  1. UrlRoutingMoudule註冊事件.
  2. 取得符合Http請求Route物件
  3. 呼叫MvcRouteHandler取得MvcHandler物件
  4. 執行MvcHandlerProcessReqeust方法

下面會陸續介紹MVC是如何取得Controller物件

此文作者:Daniel Shih(石頭)
此文地址https://isdaniel.github.io/ithelp-day10/
版權聲明:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!


如果本文對您幫助很大,可街口支付斗內鼓勵石頭^^