ASP.NET 源碼分析之Routing
最後更新:2018-12-05
來源:互聯網
上載者:User
ASP.NET MVC(以下簡稱MVC)中的表單路由在目前的版本中(RC1)實際上使用的是System.Web.Routing(.NET SP1)。
關於System.Web.Routing的單獨詳解可以參看:http://msdn.microsoft.com/zh-cn/magazine/2009.01.extremeaspnet.aspx 的“使用 ASP.NET Web Form路由”。這裡主要是配合ASP.NET MVC再來分析分析。
MVC路由和以前我們在ASP.NET中進行URL重寫(http://msdn.microsoft.com/zh-cn/library/ms972974.aspx)類似的是都是通過HTTP模組來實現的。至於兩者的區別可以參看:使用 ASP.NET Web Form路由(http://msdn.microsoft.com/zh-cn/magazine/2009.01.extremeaspnet.aspx)。
核心代碼:System.Web.Routing命名空間的UrlRoutingModule以及相關的類。
protected virtual void Init(HttpApplication application)
{
//BeginReques、AuthenticateRequest、AuthorizeRequestCache、ResolveRequestCache事件發生之後
//PostResolveRequestCache事件正好是在未給HttpContent設定Http處理常式的前一個事件
application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
//PostMapRequestHandler事件發生時,會為HttpContent設定Http處理常式,所以在該事件中設定自訂Http處理常式最合適不過了
application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
}
private void OnApplicationPostMapRequestHandler(object sender, EventArgs e)
{
//將當前HttpContent封裝成HttpContextWrapper對象並賦給HttpContextWrapper的父類HttpContextBase
HttpContextBase context = new System.Web.HttpContextWrapper(((HttpApplication) sender).Context);
this.PostMapRequestHandler(context);
}
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
HttpContextBase context = new System.Web.HttpContextWrapper(((HttpApplication) sender).Context);
this.PostResolveRequestCache(context);
}
public virtual void PostMapRequestHandler(HttpContextBase context)
{
//如果PostResolveRequestCache事件處理方法中設定了路由資訊,則根據路由中的配置重寫URL,並將HTTP處理常式設定為路由中的配置中的HTTP處理常式。
//在MVC中,HTTP處理常式設定為MvcHandler對象(註:MvcHandler對象的RequestContext屬性已經被賦值為System.Web.Routing.RequestContext對象)
RequestData data = (RequestData) context.Items[_requestDataKey];
if (data != null)
{
context.RewritePath(data.OriginalPath);
context.Handler = data.HttpHandler;
}
}
public virtual void PostResolveRequestCache(HttpContextBase context)
{
//this.RouteCollection 是 UrlRoutingModule的公用屬性,其傳回型別就是System.Web.Routing.RouteCollection
//this.RouteCollection 屬性的get方法中,通過RouteTable類的靜態屬性Routes返回一個單件的RouteCollection(雖然表面上看RouteTable不象使用單件模式,由於路由表是全域的,所以還是單件。)
//調用RouteCollection對象的GetRouteData(HttpContextBase httpContext)方法。該方法遍曆自身,搜尋時候與URL匹配的RouteData,如果不匹配返回null
//如果要瞭解具體的搜尋步驟,可以查看RouteCollection類的GetRouteData方法以及Route類的GetRouteData方法
RouteData routeData = this.RouteCollection.GetRouteData(context);
//如果搜尋到匹配的路由配置
if (routeData != null)
{
//首先檢查路由配置中是否設定了路由處理常式(註:路由處理常式中包含HTTP處理常式),在MVC中RouteData的RouteHandler屬性返回的是MvcRouteHandler對象
IRouteHandler routeHandler = routeData.RouteHandler;
if (routeHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
}
//StopRoutingHandler類阻止路由處理特定請求
if (!(routeHandler is StopRoutingHandler))
{
//RequestContext類其實就是將一個HttpContextBase對象和一個RouteData封裝在一起
RequestContext requestContext = new RequestContext(context, routeData);
//這裡通過路由處理常式的GetHttpHandler方法擷取HTTP處理常式,在MVC中IRouteHandler的GetHttpHandler方法返回的是MvcHandler對象,並將requestContext作為參數傳給了該對象
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
}
//執行個體化一個RequestData對象來儲存請求路徑和HTTP處理常式,並將之存入當前HttpContent的Item集合中
context.Items[_requestDataKey] = new RequestData { OriginalPath = context.Request.Path, HttpHandler = httpHandler };
//MVC 在 web.config 為 IIS 7.0 加了如下配置:
//<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
//轉:這是為了使路由引擎能夠在 IIS 7.0 中進行路由所採用的一種簡單解決方案。實際上 UrlRouting 模組會將傳入 URL 重寫為 ~/UrlRouting.axd,而它會將 URL 重寫回原始的傳入 URL。
context.RewritePath("~/UrlRouting.axd");
}
}
}
public RouteCollection RouteCollection
{
get
{
if (this._routeCollection == null)
{
this._routeCollection = RouteTable.Routes;
}
return this._routeCollection;
}
set
{
this._routeCollection = value;
}
}
private class RequestData
{
[CompilerGenerated]
private IHttpHandler _HttpHandler;
[CompilerGenerated]
private string _OriginalPath;
public IHttpHandler HttpHandler
{
[CompilerGenerated]
get
{
return this._HttpHandler;
}
[CompilerGenerated]
set
{
this._HttpHandler = value;
}
}
public string OriginalPath
{
[CompilerGenerated]
get
{
return this._OriginalPath;
}
[CompilerGenerated]
set
{
this._OriginalPath = value;
}
}
}