MVC路由解析---MapRoute
文章引导
引言
前面我们讲了IgnoreRoute链接
现在我们讲讲核心的MapRoute,还是提前准备Reflection工具,若是没准备,可以看“”MVC路由深入详解1---IgnoreRoute”中的System.Web.dll源码
一.RouteCollection
我们来看看RouteCollection.MapRoute,截图如下:
相信大家看到了RouteCollectionExtensions是一个静态类,是对RouteCollection的扩展(关于扩展方法的大家可以百度,此处不做详细描述)。好家伙,我们看看这个扩展方法走向何方(这个时候就是Reflection发挥作用的时候了)。
引用“”MVC路由深入详解1---IgnoreRoute”中的内容,看看MapRoute的参数传入的是什么:
name: "Default"
url: "{controller}/{action}/{id}"
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } --->这是个匿名类型
我们看看扩展方法去了哪里:
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults) => routes.MapRoute(name, url, defaults, null);
我们接着往下走
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints) =>routes.MapRoute(name, url, defaults, constraints, null);
接着
public Route MapRoute(string name,string url,object defaults,object constraints=null,string[] param=null)
{
if(url==null)
{
throw new ArgumentNullException("url");
}
Route route = new Route(url, new MvcRouteHandler())
{
Defaults=CreateRouteValueDictionaryUncached(defaults),
Constraints=CreateRouteValueDictionaryUncached(constraints),
DataTokens=new System.Web.Routing.RouteValueDictionary()
};
ConstraintValidation.Validate(route);
if ((param != null) && (param.Length > ))
{
route.DataTokens["Namespaces"] = param;
}
Add(name, route);
return route;
}
上面新建了一个Route,Route就是一条具体的路由 ,new Route(url, new MvcRouteHandler())传入规则url和new MvcRouteHandler()。
二.CreateRouteValueDictionaryUncached
private static System.Web.Routing.RouteValueDictionary CreateRouteValueDictionaryUncached(object values)
{
IDictionary<string, object> dictionary = values as IDictionary<string, object>;
if (dictionary != null)
{
return new System.Web.Routing.RouteValueDictionary(dictionary);
}
return System.Web.WebPages.TypeHelper.ObjectToDictionaryUncached(values);
}
三.MvcRouteHandler
我们继续拆解MvcRouteHandler
public class MvcRouteHandler: System.Web.Routing.IRouteHandler
{
System.Web.Mvc.IControllerFactory _controllerFactory;
public MvcRouteHandler() { }
public MvcRouteHandler(System.Web.Mvc.IControllerFactory controllFactory)
{
_controllerFactory = controllFactory;
}
protected virtual IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
//SetSessionStateBehavior:在派生类重写时,设置支持HTTP请求所必须的会话状态行为的类型
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}
IHttpHandler System.Web.Routing.IRouteHandler.GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
return GetHttpHandler(requestContext);
} protected virtual System.Web.SessionState.SessionStateBehavior GetSessionStateBehavior(System.Web.Routing.RequestContext requestContext)
{
string str = (string)requestContext.RouteData.Values["controller"];
if (string.IsNullOrEmpty(str))
{
throw new InvalidOperationException(System.Web.Mvc.Properties.MvcResources.MvcRouteHandler_RouteValuesHasNoController);
}
IControllerFactory factory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
return factory.GetControllerSessionBehavior(requestContext, str);
}
}
四.RouteValueDictionary
RouteValueDictionary是对Dictionary<string,object>进行包装,下面是RouteValueDictionary拆解
public RouteValueDictionary(object values)
{
this._dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
this.AddValues(values);
}
private void AddValues(object values)
{
if (values != null)
{
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
{
object obj2 = descriptor.GetValue(values);
this.Add(descriptor.Name, obj2);
}
}
}
我们来看看效果
五.Add(name,route)
我们来看看这个Add方法:
public void Add(string name, RouteBase item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
if (!string.IsNullOrEmpty(name) && this._namedMap.ContainsKey(name))
{
object[] args = new object[] { name };
//throw new ArgumentException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("RouteCollection_DuplicateName"), args), "name");
}
base.Add(item);
if (!string.IsNullOrEmpty(name))
{
this._namedMap[name] = item;
}
}
里面做了重复路由名称验证,Add方法的第二个参数是RouteBase,我们看看MapRoute方法里传入给Add方法的参数是Route。Route是继承于RouteBase,RouteBase是一个抽象类,这个类是为继承类服务的,里面定义了GetRouteData和GetVirtualPath两个抽象方法。
GetRouteData:解析请求url,提取数据,如:/home/index 得到:controller/home,action/index提取得到的数据会包装成RouteData
GetVirtualPath:生成URL
六.RouteBase Route
public abstract class RouteBase
{
// Methods
protected RouteBase();
public abstract RouteData GetRouteData(HttpContextBase httpContext);
public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
}
public class Route : RouteBase
{
// Fields
private ParsedRoute _parsedRoute;
private string _url;
private const string HttpMethodParameterName = "httpMethod"; // Methods
public Route(string url, IRouteHandler routeHandler);
public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler);
public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler);
public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler);
public override RouteData GetRouteData(HttpContextBase httpContext);
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
private bool ProcessConstraints(HttpContextBase httpContext, RouteValueDictionary values, RouteDirection routeDirection); // Properties
public RouteValueDictionary Constraints { get; set; }
public RouteValueDictionary DataTokens { get; set; }
public RouteValueDictionary Defaults { get; set; }
public IRouteHandler RouteHandler { get; set; }
public string Url { get; set; }
}
Route添加了几个属性
Constraints:保存约束规则,最终保存为RouteValueDictionary
DataTokens:附加参数,指定controller的空间命名也放在这里。
Defaults:保存规则的默认值
url:规则URL
我们来看看GetRouteData,我们看看RouteData routeData=RouteCollection.GetRouteData(context)。
public RouteData GetRouteData(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
if (httpContext.Request == null)
{
throw new ArgumentException(RoutingResources.RouteTable_ContextMissingRequest, "httpContext");
}
if (!this.RouteExistingFiles)
{
string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (((appRelativeCurrentExecutionFilePath != "~/") && (this._vpp != null)) && (this._vpp.FileExists(appRelativeCurrentExecutionFilePath) || this._vpp.DirectoryExists(appRelativeCurrentExecutionFilePath)))
{
return null;
}
}
using (this.GetReadLock())
{
foreach (RouteBase base2 in this)
{
RouteData routeData = base2.GetRouteData(httpContext);
if (routeData != null)
{
return routeData;
}
}
}
return null;
}
上述代码中最后通过递归遍历自己所有的路由规则,分别调用我们所有注册在RouteTable.Routes--->RouteCollection。
我们还注意到上面有这么一段:

{
string appRelativeCurrentExecutionFilePath = httpContext.Request.AppRelativeCurrentExecutionFilePath;
if (((appRelativeCurrentExecutionFilePath != "~/") && (this._vpp != null)) && (this._vpp.FileExists(appRelativeCurrentExecutionFilePath) || this._vpp.DirectoryExists(appRelativeCurrentExecutionFilePath)))
{
return null;
}
}

RouteCollection 有这么一个属性RouteExistingFiles.当为false时,就检测请求的路径地址是否己经存在文件或目录,如果存在,则直接不走路由了,直接返回null,默认就是false,我们可以实验一下。当然这里是忽略了根目录的,不然默认我们 http://www.xxx.com/ 也不能访问了。

{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new string[] { "MVCTest.Controllers" }
);
}

这里是默认的路由注册,按理说我们访问 home 时,会去到 home controller 的 index,但是我们在在项目里加一个 home 目录,如下图。
我们再访问:http://localhost:2144/home/ 我们发现,无法找到该资源,也就是检测到home这个目录存在时,就不走路由了。
为尊重原创,本文的编写参考了以下博文和文章:
程序园: http://www.cnblogs.com/lindaohui/archive/2012/08/31/2664047.html
MVC路由解析---MapRoute的更多相关文章
- MVC路由解析---IgnoreRoute
MVC路由解析---IgnoreRoute 文章引导 MVC路由解析---IgnoreRoute MVC路由解析---MapRoute MVC路由解析---UrlRoutingModule Are ...
- MVC路由解析---UrlRoutingModule
文章引导 MVC路由解析---IgnoreRoute MVC路由解析---MapRoute MVC路由解析---UrlRoutingModule Area的使用 引言: 此文全文内容90%转自 一.前 ...
- AspNet Mvc 路由解析中添加.html 等后缀 出现404错误的解决办法
使用Mvc 有时候我们希望,浏览地址以.html .htm 等后缀名进行结尾. 于是我们就在RouteConfig 中修改路由配置信息,修改后的代码如下 routes.IgnoreRoute(&quo ...
- ASP.NET MVC路由解析
继续往下看<ASP.NET MVC5框架揭秘>. ASP.NET系统通过注册路由和现有的物理文件路径发生映射.而对于ASP.NET MVC来说,请求的是某个Controller中的具体的A ...
- c# mvc 路由规则学习片段
1.初步接触mvc 路由 routes.MapRoute( "CM", "CM/{controller}/{act ...
- 在ASP.NET非MVC环境中(WebForm中)构造MVC的URL参数,以及如何根据URL解析出匹配到MVC路由的Controller和Action
目前项目中有个需求,需要在WebForm中去构造MVC的URL信息,这里写了一个帮助类可以在ASP.NET非MVC环境中(WebForm中)构造MVC的URL信息,主要就是借助当前Http上下文去构造 ...
- 2016/5/6 thinkphp ①框架 ② 框架项目部署 ③MVC模式 ④控制器访问及路由解析 ⑤开发和生产模式 ⑥控制器和对应方法创建 ⑦视图模板文件创建 ⑧url地址大小写设置 ⑨空操作空控制器 ⑩项目分组
真实项目开发步骤: 多人同时开发项目,协作开发项目.分工合理.效率有提高(代码风格不一样.分工不好) 测试阶段 上线运行 对项目进行维护.修改.升级(单个人维护项目,十分困难,代码风格不一样) 项目稳 ...
- 【基础】MVC路由规则
一.RouteData解析过程 在ASP.NET MVC中,服务器收到来自客户端的请求后,会经过一些列的处理拿到请求的数据,比如在Pipeline 管线事件中,通过订阅适当的事件,将HttpConte ...
- ASP.NET MVC 路由(一)
ASP.NET MVC路由(一) 前言 从这一章开始,我们即将进入MVC的世界,在学习MVC的过程中在网上搜索了一下,资料还是蛮多的,只不过对于我这样的初学者来看还是有点难度,自己就想看到有一篇引导性 ...
随机推荐
- 全面了解python中的类,对象,方法,属性
全面了解python中的类,对象,方法,属性 python中一切皆为对象,所谓对象:我自己就是一个对象,我玩的电脑就是对象,坐着的椅子就是对象,家里养的小狗也是一个对象...... 我们通过描述属性( ...
- 加载的DAL数据访问层的类型
using System; using System.Collections; using System.Reflection; using CSFrameworkV4_5.Core; using C ...
- 在线清空nohup.out内容
通过 cat /dev/null > filename 命令可以在线清空nohup.out里的内容
- PAT甲级【2019年9月考题】——A1163 PostfixExpression【25】
7-3 Postfix Expression (25 分) Given a syntax tree (binary), you are supposed to output the correspon ...
- excel cannot access the file there are several possible reasons
original link Microsoft Office Excel cannot access the file ‘c:\file.xlsx’. There are several possib ...
- .NET/VB.NET: solving the error “The system cannot find the file specified.” “\Temp\.NETFramework,Version=v4.0.AssemblyAttributes.vb”
Source Link Bumped into this error a while ago in Visual Studio 2010: Kind Error Number 80 Descripti ...
- Ubuntu添加与删除PPA源
目录 PPA,英文全称为 Personal Package Archives,即个人软件包档案.是 Ubuntu Launchpad 网站提供的一项源服务,允许个人用户上传软件源代码,通过 Launc ...
- php分割url,获取参数query
#测试网址: http://localhost/blog/testurl.php?id=5 //获取域名或主机地址echo $_SERVER['HTTP_HOST']."<br> ...
- 【学习总结】Python-3-身份运算符 is 与 == 区别
参考:菜鸟教程-Python3运算符 身份运算符 is 和 is not:用于比较两个对象的存储单元 判断两个标识符是不是引用自相同或不同对象,返回一个布尔值 对于"同一个对象"中 ...
- js常用扩展方法
在日常的开发过程中,经常会碰到javaScript原生对象方法不够用的情况,所以经常会对javaScript原生方法进行扩展.下面就是在实际工作时,经常使用的一些方法,做一下记录,有需要的可以拿去. ...