文章出處

上一篇 說到了路由事件注冊以及路由表的生成, 前面 也解析到了, 管道事件的建立, 那么接下來, 肯定就是要調用執行這些事件了, 這些就不表了, 我已經得到我想要的部分了, 接下來, 在執行這些管道事件的時候, 肯定就會執行到之前 UrlRoutingModule注冊的方法. 接下來, 就看一下, 這個事件干了些什么. 

一、OnApplicationPostResolveRequestCache 方法

private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
    HttpApplication application = (HttpApplication) sender;
    HttpContextBase context = new HttpContextWrapper(application.Context);
    this.PostResolveRequestCache(context);
}

這里調用了自己(UrlRoutingModule)的 PostResolveRequestCache 方法. 

public virtual void PostResolveRequestCache(HttpContextBase context)
{
   //根據http上下文去 之前生成的路由表中查找匹配的路由 RouteData routeData = this.RouteCollection.GetRouteData(context); if (routeData != null) {
     //這里返回的 IRouteHandler 其實就是 MvcRouteHandler(上一篇)有提到過
     //這個MvcRouteHandler中, 就有一個方法, 用來返回 IHttpHander的, 其實就是返回的 MvcHandler
IRouteHandler routeHandler = routeData.RouteHandler; if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
           SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0])); }
     //在注冊路由的時候, Ignore方式注冊的, 會返回StopRoutingHandler if (!(routeHandler is StopRoutingHandler)) {
       //在這里, 首先創建了請求上下文 RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext;
        //在這里獲取到MVC的處理接口, 就是 MvcHandler IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); if (httpHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture,
             SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() })); } if (httpHandler is UrlAuthFailureHandler) { if (!FormsAuthenticationModule.FormsAuthRequired) { throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3")); } UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); } else {
          //將 MvcHandler 存入 HttpContext 對象的 _remapHandler 屬性中 context.RemapHandler(httpHandler); } } } }

 按照順序, 看上面我標紅的接個方法.

 

1. GetRouteData()方法

//RouteCollection
public
RouteData GetRouteData(HttpContextBase httpContext) { if (httpContext == null) { throw new ArgumentNullException("httpContext"); } if (httpContext.Request == null) { throw new ArgumentException(SR.GetString("RouteTable_ContextMissingRequest"), "httpContext"); } if (base.Count != 0) { bool flag = false; bool flag2 = false; if (!this.RouteExistingFiles) { flag = this.IsRouteToExistingFile(httpContext); flag2 = true; if (flag) { return null; } } using (this.GetReadLock()) { foreach (RouteBase base2 in this) { RouteData routeData = base2.GetRouteData(httpContext); if (routeData != null) { if (!base2.RouteExistingFiles) { if (!flag2) { flag = this.IsRouteToExistingFile(httpContext); flag2 = true; } if (flag) { return null; } } return routeData; } } } } return null; }

接著看, 這里調用了 Route 類的 GetRouteData() 方法

public override RouteData GetRouteData(HttpContextBase httpContext)
{
    string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
    RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);
    if (values == null)
    {
        return null;
    }
    RouteData data = new RouteData(this, this.RouteHandler);
    if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))
    {
        return null;
    }
    foreach (KeyValuePair<string, object> pair in values)
    {
        data.Values.Add(pair.Key, pair.Value);
    }
    if (this.DataTokens != null)
    {
        foreach (KeyValuePair<string, object> pair2 in this.DataTokens)
        {
            data.DataTokens[pair2.Key] = pair2.Value;
        }
    }
    return data;
}

這里就會根據之前注冊路由的限制條件去匹配路由了. 將最后匹配到的那個路由返回.

 

2. GetHttpHandler()方法

這里會調用 MvcRouteHandler 的 GetHttpHandler 方法, 前面篇章提過的.

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
    requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
    return new MvcHandler(requestContext);
}

返回一個 MvcHandler .

 

3. RemapHandler()方法

這里會調用 HttpContext 的RemapHandler 方法.

public void RemapHandler(IHttpHandler handler)
{
    this.EnsureHasNotTransitionedToWebSocket();
    IIS7WorkerRequest request = this._wr as IIS7WorkerRequest;
    if (request != null)
    {
        if (this._notificationContext.CurrentNotification >= RequestNotification.MapRequestHandler)
        {
            throw new InvalidOperationException(SR.GetString("Invoke_before_pipeline_event",
         new object[] { "HttpContext.RemapHandler", "HttpApplication.MapRequestHandler" })); } string handlerType = null; string handlerName = null; if (handler != null) { Type type = handler.GetType(); handlerType = type.AssemblyQualifiedName; handlerName = type.FullName; } request.SetRemapHandler(handlerType, handlerName); } this._remapHandler = handler; }

這里主要就是看最后一句了, 將 mvchandler存入到 HttpContext._remapHandler 中

 

到這里, 其實就能看到 路由匹配的過程以及獲取到 mvc處理程序(這個是入口). 

 

二、路由匹配

在分析路由的時候, 可以借助一個插件 : RouteDebugger, 獲取方式為, 在vs程序包控制臺中, 執行以下命令

PM> Install-Package routedebugger

添加完之后, 程序會自動在web.config中添加如下配置:

<add key="RouteDebugger:Enabled" value="true" />

我們只需要直接運行程序就好了. 先看一張效果圖:

在圖上, 能清晰的看到, 匹配過程中, 與其中的哪一個路由能匹配的上. 哪一些不能匹配上.

兩個小問題:

  如果有兩個匹配規則相同, 但是路由名不同的, 會匹配上哪一個呢?

    哪一個在前面注冊的, 就回匹配到哪一個, 后面的不會繼續匹配.

  那會不會有匹配規則不同, 但是路由名相同的呢?

    一般在使用key的時候, 都是要保證key的唯一性, 路由同樣如此, 路由名不能重復, 必須唯一, 否則會報錯.

有興趣的朋友, 可以去了解下

目錄已同步


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()