ASP.NET MVC 1.0 流程分析(System.Web.Routing)【zz】

來源:互聯網
上載者:User

MVC 依賴 System.Web.Routing 處理請求路徑解析,也就是說整個流程的起始是由 System.Web.Routing.UrlRoutingModule 開始的。 

Web.config 
<httpModules> 
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, ..."/> 
</httpModules> 

那麼我們就看看這個 UrlRoutingModule 內部都做了什麼。 

public class UrlRoutingModule : IHttpModule 

protected virtual void Init(HttpApplication application) 

application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); 
application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler); 

訂閱了兩個 HttpApplication 事件。在 ASP.NET 應用程式生命週期中 PostResolveRequestCache 會在 PostMapRequestHandler 之前觸發,最後是 IHttpHandler.ProcessRequest() 完成最終的請求處理。 

通過對請求上下文進行封裝,進一步進行處理。 

public class UrlRoutingModule : IHttpModule 

private void OnApplicationPostMapRequestHandler(object sender, EventArgs e) 

HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context); 
this.PostMapRequestHandler(context); 

private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) 

HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context); 
this.PostResolveRequestCache(context); 

首先, PostResolveRequestCache 被執行。 

public class UrlRoutingModule : IHttpModule 

public virtual void PostResolveRequestCache(HttpContextBase context) 

RouteData routeData = this.RouteCollection.GetRouteData(context); 

if (routeData != null) 

IRouteHandler routeHandler = routeData.RouteHandler; 

... 

if (!(routeHandler is StopRoutingHandler)) 

RequestContext requestContext = new RequestContext(context, routeData); 
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 

... 

RequestData data2 = new RequestData(); 
data2.OriginalPath = context.Request.Path; 
data2.HttpHandler = httpHandler; 
context.Items[_requestDataKey] = data2; 
context.RewritePath("~/UrlRouting.axd"); 



RouteCollection 實際是對 RouteTable.Routes 的引用。 

public class UrlRoutingModule : IHttpModule 

public RouteCollection RouteCollection 

get 

if (this._routeCollection == null) 

this._routeCollection = RouteTable.Routes; 

return this._routeCollection; 

set 

this._routeCollection = value; 


好嗎,又跳了一回。 

public class RouteTable 

private static RouteCollection _instance = new RouteCollection(); 

public static RouteCollection Routes 

get 

return _instance; 



這時候,我們要提及 Global.asax.cs 中的代碼。 

public class MvcApplication : System.Web.HttpApplication 

public static void RegisterRoutes(RouteCollection routes) 

routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

routes.MapRoute( 
"Default", 
"{controller}/{action}/{id}", 
new { controller = "Home", action = "Index", id = "" } 
); 

protected void Application_Start() 

RegisterRoutes(RouteTable.Routes); 

IgnoreRoute 和 MapRoute 都是 System.Web.Mvc.dll 中提供的擴充方法。 

public static class RouteCollectionExtensions 

public static void IgnoreRoute(this RouteCollection routes, string url); 
... 
public static Route MapRoute(this RouteCollection routes, string name, string url); 
... 

唯一需要注意的是方法內部一個細節,其註冊的 IHttpHandler 是 MvcRouteHandler。 

public static class RouteCollectionExtensions 

public static Route MapRoute(this RouteCollection routes, string name, ...) 

Route <>g__initLocal1 = new Route(url, new MvcRouteHandler()); 
<>g__initLocal1.Defaults = new RouteValueDictionary(defaults); 
<>g__initLocal1.Constraints = new RouteValueDictionary(constraints); 
Route route = <>g__initLocal1; 

if ((namespaces != null) && (namespaces.Length > 0)) 

route.DataTokens = new RouteValueDictionary(); 
route.DataTokens["Namespaces"] = namespaces; 

routes.Add(name, route); 
return route; 

public static void IgnoreRoute(this RouteCollection routes, string url, object constraints) 

IgnoreRouteInternal <>g__initLocal0 = new IgnoreRouteInternal(url); 
<>g__initLocal0.Constraints = new RouteValueDictionary(constraints); 
IgnoreRouteInternal route = <>g__initLocal0; 
routes.Add(route); 

private sealed class IgnoreRouteInternal : Route 

public IgnoreRouteInternal(string url) : base(url, new StopRoutingHandler()) { } 

public class MvcRouteHandler : IRouteHandler 

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext); 
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext); 

好了,回到 UrlRoutingModule.PostResolveRequestCache。 

public class UrlRoutingModule : IHttpModule 

public virtual void PostResolveRequestCache(HttpContextBase context) 

RouteData routeData = this.RouteCollection.GetRouteData(context); 

if (routeData != null) 

IRouteHandler routeHandler = routeData.RouteHandler; 

... 

if (!(routeHandler is StopRoutingHandler)) 

RequestContext requestContext = new RequestContext(context, routeData); 
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 

... 

RequestData data2 = new RequestData(); 
data2.OriginalPath = context.Request.Path; 
data2.HttpHandler = httpHandler; 

context.Items[_requestDataKey] = data2; 
context.RewritePath("~/UrlRouting.axd"); 




在擷取 RouteData 和 MvcRouteHandler 後,調用 MvcRouteHandler.GetHttpHandler() 擷取 IHttpHandler。 

public class MvcRouteHandler : IRouteHandler 

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) 

return new MvcHandler(requestContext); 

IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) 

return this.GetHttpHandler(requestContext); 

好!MvcHandler 出現了,這意味著執行流程從 System.Web.Routing 轉到 System.Web.Mvc 的契機出現了。UrlRoutingModule.PostResolveRequestCache() 的最後將相關請求參數儲存到上下文中,還有一行奇怪的代碼,看看我們從 Microsoft Symbol Server 下載的原始碼會有什麼說明。 

具體步驟: 

1. 首先添加 PostResolveRequestCache 斷點 (我們可以為沒有原始碼的方法設定斷點)。

2. 然後下載符號檔案。 


3. 開啟原始碼。 

好了,看看原作者如何說的。 

public virtual void PostResolveRequestCache(HttpContextBase context) 

// Save data to be used later in pipeline 
context.Items[_requestDataKey] = new RequestData() 

OriginalPath = context.Request.Path, 
HttpHandler = httpHandler 
}; 

// Rewrite path to something registered as a managed handler in IIS. This is necessary so IIS7 will 
// execute our managed handler (instead of say the static file handler). 
context.RewritePath("~/UrlRouting.axd"); 

不扯閑話了,我們繼續執行流程。依照 ASP.NET HttpApplication 事件順序,接下來 UrlRoutingModule.PostMapRequestHandler() 會被執行。 

public class UrlRoutingModule : IHttpModule 

public virtual void PostMapRequestHandler(HttpContextBase context) 

RequestData data = (RequestData) context.Items[_requestDataKey]; 
if (data != null) 

context.RewritePath(data.OriginalPath); 
context.Handler = data.HttpHandler; 


RequestData data 顯然就是 PostResolveRequestCache() 儲存的資料。通過將 HttpContext.Handler 設定為 MvcHandler,使得後續執行得以進行。對了,原作者對於這個方法的 RewritePath 也有說明。 

public virtual void PostMapRequestHandler(HttpContextBase context) 

RequestData requestData = (RequestData)context.Items[_requestDataKey]; 

if (requestData != null) 

// Rewrite the path back to its original value, so the request handler only sees the original path. 
context.RewritePath(requestData.OriginalPath); 

// Set Context.Handler to the IHttpHandler determined earlier in the pipeline. 
context.Handler = requestData.HttpHandler; 

好了,有關 System.Web.Routing 的流程分析就到這了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.