上一篇 说到了路由事件注册以及路由表的生成, 前面 也解析到了, 管道事件的建立, 那么接下来, 肯定就是要调用执行这些事件了, 这些就不表了, 我已经得到我想要的部分了, 接下来, 在执行这些管道事件的时候, 肯定就会执行到之前 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 != )
{
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() + 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的唯一性, 路由同样如此, 路由名不能重复, 必须唯一, 否则会报错.

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

目录已同步

MVC源码分析 - 路由匹配的更多相关文章

  1. ASP.NET MVC源码分析

    MVC4 源码分析(Visual studio 2012/2013) HttpModule中重要的UrlRoutingModule 9:this.OnApplicationPostResolveReq ...

  2. ASP.NET MVC 源码分析(一)

    ASP.NET MVC 源码分析(一) 直接上图: 我们先来看Core的设计: 从项目结构来看,asp.net.mvc.core有以下目录: ActionConstraints:action限制相关 ...

  3. 精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  4. 精尽Spring MVC源码分析 - HandlerMapping 组件(一)之 AbstractHandlerMapping

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  5. 精尽Spring MVC源码分析 - HandlerMapping 组件(二)之 HandlerInterceptor 拦截器

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  6. 精尽Spring MVC源码分析 - HandlerMapping 组件(三)之 AbstractHandlerMethodMapping

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  7. 精尽Spring MVC源码分析 - HandlerMapping 组件(四)之 AbstractUrlHandlerMapping

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  8. 精尽Spring MVC源码分析 - HandlerExceptionResolver 组件

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  9. 精尽Spring MVC源码分析 - LocaleResolver 组件

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

随机推荐

  1. C语言实现全排列

    实现全排列,递归实现 #include <stdio.h> #include <stdlib.h> ; void swap(int *a, int *b) { int m; m ...

  2. 用批处理编译*.sln工程

    原文:用批处理编译*.sln工程 批处理是直接调用Microsoft Visual Studio 8\Common7\IDE\ 目录内的 devenv.exe ,它启动后就是IDE,提供的参数如下: ...

  3. C#实现RSA加密和解密详解

    原文:C#实现RSA加密和解密详解 RSA加密解密源码: Code highlighting produced by Actipro CodeHighlighter (freeware) http:/ ...

  4. 使用rem设计移动端自适应页面一(转载)

    1.困扰多时的问题 在这之前做Web App开发的的时候,在自适应方面一般都是宽度通过百分比,高度以iPhone6跟iPhone5之间的一个平衡值写死,我们的设计稿都是iPhone5的640 * 11 ...

  5. 安装系统提示选中的磁盘具有MBR分区表

    引用:http://jingyan.baidu.com/article/ff42efa9693e88c19e22020c.html 进入bios看到  UEFI状态时  Enabled 启用状态,那么 ...

  6. Smarty注释代码

    所有的smarty模板标签都被加上了定界符. 默认情况下是 { 和},但它们是可被改变的. 例如,我们假定你在使用默认定界符. 在smarty里,所有定界符以外的内容都是静态输出的,或者称之为不可改变 ...

  7. 使用pager进行分页

    pager jar网址:http://java2s.com/Code/Jar/t/Downloadtaglibspagejar.htm package com.binary.entity; impor ...

  8. PHP中使用Ajax

    在PHP中使用Ajax来获取数据库中的数据,从而达到不刷新页面就可以获取. 首先在JS中定义变量如: var xmlHttp;function getXmlHttp(){ if(window.Acti ...

  9. 开启apache服务

    安装后如果需要手动添加Sevice,可以按照如下方法: Apache版本:httpd-2.2.15_win32 Apache Service Monitor 提示:“No services insta ...

  10. MFC圆角背景移动边角底色毛刺解决方案

    CRect rc; Graphics graphics(pDC->m_hDC); GetClientRect(&rc); CRgn m_rgn; if (m_pBgImage) { gr ...