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的过程中在网上搜索了一下,资料还是蛮多的,只不过对于我这样的初学者来看还是有点难度,自己就想看到有一篇引导性 ...
随机推荐
- 如何设置Windows操作系统打印机与xlpd连接
Xlpd是Xmanager中负责远程打印的软件,除了打印远程文件,它还具备很多功能,本集将具体讲解Xlpd的主要功能. 主要功能如下: 1. 支持LPD协议(RFC1179) 在RFC1179中定义 ...
- 对GridFS数据进行分片
On this page files 集合 chunks 集合 在对 GridFS 存储进行分片时,需要注意以下的情况: files 集合 大多数情况下不需要对 files 集合进行分片,这个集合通常 ...
- WEB服务端安全---注入攻击
注入攻击是web领域最为常见的攻击方式,其本质是把用户输入的数据当做代码执行,主要原因是违背了数据与代码分离原则,其发生的两个条件:用户可以控制数据输入:代码拼接了用户输入的数据,把数据当做代码执行了 ...
- k8s-启动、退出动作
vim post.yaml apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: life ...
- code for QTP and ALM
'==========================================================================' Name: connectALM' Summa ...
- .gz文件解压
有时我们明明已经使用gunzip命令解压.gz文件了,可解压生成的文件却依然无法正常读取.如输入命令gunzip HelloWorld.java.gz后,解压生成HelloWorld.java文件,却 ...
- Apache Shiro 集成Spring(二)
1.依赖: <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-cor ...
- UVALive 4728 Squares(旋转卡壳)
Squares The famous Korean IT company plans to make a digital map of the Earth with help of wireless ...
- vscode 常用命令行
Ctrl+Shift+P: 打开命令面板 打开一个新窗口: Ctrl+Shift+N 关闭窗口: Ctrl+Shift+W 新建文件 Ctrl+N 代码行缩进 Ctrl+[ . Ctrl+] 上下 ...
- ArcGIS 面要素缝隙孔洞检查代码 C# GP
public class PolygonGapChecker : CheckProgressMessageSender, IChecker, ICheckProgressChangeEvent { p ...