1.RouteTable

  RouteTable翻译过来的意思就是路由表,一个Web应用程序具有一个全局的路由表,该路由表通过System.Web.Routiing.RouteTable的静态只读属性Routes表示,该类型返回一个类型为System.Web.Routingg.RouteCollection的集合。

  RouteTable类十分的简单,如下所示

    public class RouteTable
{
private static RouteCollection _instance = new RouteCollection(); //返回一个静态只读的RouteCollection类型实例
public static RouteCollection Routes
{
get
{
return RouteTable._instance;
}
}
public RouteTable()
{
}
}

  现在我们来看一下运行时的状态

    public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes); //断点1
}
}

  下图就是当断点处于断点1时,RouteTable的状态 ,我们在这里可以很清楚的看到现在Routes属性所包含的路由条数为0,不急我们继续向下走。

2.RouteCollection

  看到名称就不难猜到,这个应该是表示路由集合,我们先来看看这个类里面有什么新奇玩意。

public class RouteCollection : Collection<RouteBase>
{
//其余省略 //是否添加首尾斜杠.默认值为 false.
public bool AppendTrailingSlash { get; set; }
//是否将 URL 转换为小写.默认值为 false.
public bool LowercaseUrls { get; set; }
//是否应处理与现有文件匹配的 URL.默认值为 false.
public bool RouteExistingFiles { get; set; }
//获取路由信息
public RouteData GetRouteData(HttpContextBase httpContext);
//获取虚拟路径信息
public VirtualPathData GetVirtualPath(RequestContext requestContext, string name, RouteValueDictionary values);
//忽略路由URL和相关约束
public void Ignore(string url, object constraints);
//添加路由
public Route MapPageRoute(string routeName, string routeUrl, string physicalFile, bool checkPhysicalUrlAccess, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens); }

  稍微了解了这个类是用来干什么的,那么我们就要接着上面的程序向下走了,当然先介绍以下RouteBase和Route类吧

3.RouteBase,Route

  在上图中我们看到了RouteBase,Route类,来说一下它们是什么吧。

  RouteBase

  RouteBase是Route类的父类,我们还是来看下它的类结构吧

public abstract class RouteBase
{
private bool _routeExistingFiles = true; // 指示 ASP.NET 路由操作是否应处理与物理文件匹配的 URL,这里默认是True,即可以使用WebForm方式请求物理文件,但是在MSDN中描述
//这个属性的默认值为False
public bool RouteExistingFiles
{
get
{
return this._routeExistingFiles;
}
set
{
this._routeExistingFiles = value;
}
} // 获取路由信息,保存在RouteData中
public abstract RouteData GetRouteData(HttpContextBase httpContext); // 获取虚拟路径信息,保存在VirtualPathData中
public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
}

  RouteURL模版模式的路由匹配规则就定义在Route中,看下类结构吧

public class Route : RouteBase
{
// 省略代码.....
private string _url;
private ParsedRoute _parsedRoute;
private const string HttpMethodParameterName = "httpMethod";
// 存储路由约束
public RouteValueDictionary Constraints
{
get;
set;
}
// 存储额外变量,但不会参与针对请求地址的匹配工作,比如Namespaces
public RouteValueDictionary DataTokens
{
get;
set;
}
// 存储为路由变量定义的默认值
public RouteValueDictionary Defaults
{
get;
set;
}
// 路由处理对象
public IRouteHandler RouteHandler
{
get;
set;
}
// URL模版
public string Url
{
get
{
return this._url ?? string.Empty;
}
set
{
this._parsedRoute = RouteParser.Parse(value);
this._url = value;
}
}
public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
{
this.Url = url;
this.Defaults = defaults;
this.Constraints = constraints;
this.DataTokens = dataTokens;
this.RouteHandler = routeHandler;
}
// 重写父类方法
public override RouteData GetRouteData(HttpContextBase httpContext)
{
string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring() + httpContext.Request.PathInfo;
RouteValueDictionary routeValueDictionary = this._parsedRoute.Match(virtualPath, this.Defaults);
if (routeValueDictionary == null)
{
return null;
}
RouteData routeData = new RouteData(this, this.RouteHandler);
if (!this.ProcessConstraints(httpContext, routeValueDictionary, RouteDirection.IncomingRequest))
{
return null;
}
foreach (KeyValuePair<string, object> current in routeValueDictionary)
{
routeData.Values.Add(current.Key, current.Value);
}
if (this.DataTokens != null)
{
foreach (KeyValuePair<string, object> current2 in this.DataTokens)
{
routeData.DataTokens[current2.Key] = current2.Value;
}
}
return routeData;
}
// 重写父类方法
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
BoundUrl boundUrl = this._parsedRoute.Bind(requestContext.RouteData.Values, values, this.Defaults, this.Constraints);
if (boundUrl == null)
{
return null;
}
if (!this.ProcessConstraints(requestContext.HttpContext, boundUrl.Values, RouteDirection.UrlGeneration))
{
return null;
}
VirtualPathData virtualPathData = new VirtualPathData(this, boundUrl.Url);
if (this.DataTokens != null)
{
foreach (KeyValuePair<string, object> current in this.DataTokens)
{
virtualPathData.DataTokens[current.Key] = current.Value;
}
}
return virtualPathData;
}
// 验证参数值是否与该参数的约束匹配
protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
IRouteConstraint routeConstraint = constraint as IRouteConstraint;
if (routeConstraint != null)
{
return routeConstraint.Match(httpContext, this, parameterName, values, routeDirection);
}
string text = constraint as string;
if (text == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_ValidationMustBeStringOrCustomConstraint"), new object[]
{
parameterName,
this.Url
}));
}
object value;
values.TryGetValue(parameterName, out value);
string input = Convert.ToString(value, CultureInfo.InvariantCulture);
string pattern = "^(" + text + ")$";
return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
}
}

  介绍完RouteBase和Route类后,我们的代码继续向下走

    public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { controller = "^H.*" },
namespaces: new[] { "SimpleMVC" }
);
}

  看上面一段代码,我们发现RouteCollection实例有两个方法,但是System.Web.Routing.RouteCollection类中并没有这两个方法,那这个怎么实现的呢?

  我们在IgnoreRoute上转到定义看下,发现我们跳转到了System.Web.Mvc.RouteCollectionExtensions这个路由集合扩展类了,在看下这个方法

    public static void IgnoreRoute(this RouteCollection routes, string url)
{
routes.IgnoreRoute(url, null);
}

  一看恍然大悟,原来是通过扩展方法,感叹下扩展方法原来是可以这么用的。

  好了,那么routes.MapRoute也肯定是通过扩展方法注入的。那我们就看下route.MaoRoute是实现的。

    public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
// MvcRouteHandler 是请求进入时使用MVC路由关键
Route route = new Route(url, new MvcRouteHandler())
{
// 存储为路由变量定义的默认值
Defaults = RouteCollectionExtensions.CreateRouteValueDictionaryUncached(defaults),
// 存储路由约束
Constraints = RouteCollectionExtensions.CreateRouteValueDictionaryUncached(constraints),
// 存储额外变量,但不会参与针对请求地址的匹配工作,比如Namespaces
DataTokens = new RouteValueDictionary()
};
ConstraintValidation.Validate(route);
if (namespaces != null && namespaces.Length > )
{
route.DataTokens["Namespaces"] = namespaces;
}
// 向RouteCollection中添加路由
routes.Add(name, route);
// 返回该路由
return route;
}

  好了,我们大概已经了解这两个扩展方法的作用了,下面我们来看看它们在运行时的状态

    public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { controller = "^H.*" },
namespaces: new[] { "SimpleMVC" }
);// 断点2
}

  我们看看当断点停留在断点2处时,类里面的状态是怎样的?如下图

  我们可以很清楚的看到RouteCollection实例包含两条由规则,这两条路由规则都是继承自System.Web.Routing.RouteBase,第一条是我们定义为忽略的路由,类型是System.Web.Mvc.RouteCollectionExtensions.IgnoreRouteInternal,该类型继承子System.Web.Routing.Route,第二条则是我们定义的有效的路由,类型是System.Web.Routing.Route。

  我们在深入看下第二条有效的路由信息

  通过上图,可以非常明显的看出,哪些数据存储到了哪些属性里面,可以有个直观的理解。

4.关系

  好了,我们的程序需要继续向下走,执行完RegisterRoutes方法后,我们又回到了Application_Start方法。

        protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes); // 断点1
} // 断点3

  我们在断点3出看下各类的状态,总结下RouteTable,RouteCollection,RouteBase,Route4个类之间的关系,如下图所示

  下面是一张RouteTable,RouteCollection,RouteBase,Route4个类关系图

  

  

ASP.NET MVC 请求流程:Route的更多相关文章

  1. asp.net mvc请求流程

    收对应用程序的第一个请求 > 执行路由 > 创建 MVC 请求处理程序 > 创建控制器 > 执行控制器 > 调用操作 > 执行结果

  2. ASP.NET MVC 请求流程:Controller

    1.请求进入时,.NET Framework就找出所有的HttpModule,以此调用它们的Init方法,如下图所示,我们重点关注"UrlRoutingModule-4.0"的Ht ...

  3. ASP.NET MVC 请求流程

    一.应用程序启动 1.Application_Start方法,程序启动 2.RegisterRoutes方法,注册路由 3.System.Web.Mvc.RouteCollectionExtensio ...

  4. .NET MVC请求流程

    ASP.NET MVC 请求流程:Controller MvcHandler Action Action参数赋值 .NET MVC权限设计思考之切入点

  5. ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程

    好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人>: --> 开篇:上一篇 ...

  6. ASP.Net MVC请求处理流程

    ASP.Net MVC请求处理流程 好听的歌 我一直觉得看一篇文章再听一首好听的歌,真是种享受.于是,我在这里嵌入一首好听的歌,当然你觉得不想听的话可以点击停止,歌曲 from 王菲 <梦中人& ...

  7. asp.net mvc 请求处理流程,记录一下。

    asp.net mvc 请求处理流程,记录一下.

  8. 【MVC】ASP.NET MVC 请求生命周期

    当一个asp.net mvc应用程序提出请求,为了响应请求,包含一些请求执行流程步骤! 在asp.net mvc应用程序Http request和Http response 过程中,主要包含8个步骤: ...

  9. Asp.net Mvc 请求是如何到达 MvcHandler的——UrlRoutingModule、MvcRouteHandler分析,并造个轮子

    这个是转载自:http://www.cnblogs.com/keyindex/archive/2012/08/11/2634005.html(那个比较容易忘记,希望博主不要生气的) 前言 本文假定读者 ...

随机推荐

  1. [Unity3D入门]入门级游戏项目"坦克狙击手"更新

    [Unity3D入门]入门级游戏项目"坦克狙击手"更新 在上一篇中我分享了一个尚未完全写好的入门级unity3d项目"坦克狙击手". 本文介绍最新版的" ...

  2. CSS的两个小知识点 伪类选择器和display:table-cell

    li:first-child {color:red} li:nth-child(3n) {color: red} 在对nth-child传参的时候,已经直接用公式,3n就表示3的倍数.多用伪类和伪元素 ...

  3. 缓存篇~第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)

    返回目录 上一讲主要是说如何将数据集存储到redis服务器里,而今天主要说的是缓存里的键名,我们习惯叫它key. redis或者其它缓存组件实现的存储机制里,它将很多方法对应的数据集存储在一个公共的空 ...

  4. 爱上MVC~在Views的多级文件夹

    回到目录 在MVC里,你的控制器对应的视图一般是在Views目录,而如果希望在Views里再分几个模块文件夹默认是不允许的,我们需要做一下设置,就可以实现Views下的多次文件夹层次了,例如,我们有产 ...

  5. 在Windows下安装Memcached

    Windows下的Memcache安装: 需要运行命令行工具cmd 请以管理员权限运行 开始->附件->命令提示符,以管理员身份运行 假如当前C:\windows\system32,输入c ...

  6. 我的Eclipse快捷键.

    所谓“工欲善其事必先利其器”,程序写多了,对于快捷键总有些特别的偏爱.在众多编辑器中,Eclipse算是用的比较多,也是最熟的. 最常用(也是最爱的:)) Ctrl+’ :  自动完成提示.这个快捷键 ...

  7. PHP将富文本编辑后的内容,去除样式图片等只保留txt文本内容

    1.从数据库读取富文本内容样式如下: <p style=";text-indent: 0;padding: 0;line-height: 26px"><span ...

  8. 当你还在纠结于ORM的性能时,我已经远远的把你抛在脑后

    最近找工作面试,问到一些过去的工作和项目经验.我把公司用到的ORM框架(LLBL Gen)拿出来谈一谈,说一下他的优势,对方却一直追问ORM的好处,性能方面的问题,让我有时候都不知道如何回答,产生了不 ...

  9. PCurve - Curve on Surface

    PCurve - Curve on Surface eryar@163.com Abstract. 本文通过给出曲面上曲线PCurve的定义来对OpenCascade中的Curve On Surfac ...

  10. poj2060Taxi Cab Scheme(二分图匹配)

    /* 题意: 出租车 有一个出发的时间,从点(a, b)到点(c, d),时间为 abs(a-c)+abs(b-d)! 一辆车可以在运完一个乘客后运另一个乘客, 条件是此车要在预约开始前一分钟之前到达 ...