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的过程中在网上搜索了一下,资料还是蛮多的,只不过对于我这样的初学者来看还是有点难度,自己就想看到有一篇引导性 ...
随机推荐
- 测开之路四十二:常用的jquery事件
$(‘selector’).click() 触发点击事件$(‘selector’).click(function) 添加点击事件$(‘selector’).dbclick() 触发双击事件$(‘sel ...
- 如何消去delphi Stringgrid重绘时产生重影
procedure TForm1.Stringgrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGrid ...
- 用threading 解决 gunicorn worker timeout
产生worker timeout 的背景 while 1: ..... time.sleep(1) gunicorn运行起来,只等待了30s,就卡住了,没报任何异常或err,查了gunicorn 官方 ...
- python 装饰器 第五步(2):带有返回值得装饰器
#第五步:带有返回值的装饰器 把第四步复制过来 #用于扩展基本函数的函数 def kuozhan(func): #内部函数(扩展之后的eat函数) def neweat(): #以下三步就是扩展之后的 ...
- [fW]中断处理函数数组interrupt[]初始化
中断处理函数数组interrupt[]初始化 2011-05-13 15:51:40 分类: LINUX 在系统初始化期间,trap_init()函数将对中断描述符表IDT进行第二次初始化(第一次只是 ...
- 定时任务crond介绍
定时任务cornd crond介绍: crond是linux系统中用来定期(或周期性)执行命令或指定程序任务脚本的一种程序. 查看crontab帮助: [root@db01 ~]# crontab - ...
- MVC的布局页,视图布局页和分布页的使用
一,结构如下图 二,布局页和视图布局页 1>使用方法一 _ViewStart.cshtml @{ Layout = "~/Views/Shared/_Layout.cshtml&quo ...
- fusionCharts图表在客户端导出图片
前提:要具备三个文件:FusionCharts.js / FusionChartsExportComponent.js / FCExporter.swf 1.引用 js 文件 <script t ...
- 对于一键退出APP功能实现的技术探讨
在Android的开发过程中,会经常存在“一键退出APP”的需求.经过一段时间的整理,其主要实现方式有以下几种. 本质:一键结束当前APP的所有activity&一键结束当前APP进程,两者合 ...
- java -jar 中文乱码
java -Dfile.encoding=utf-8 -jar demo.jar 添加编码即可