新建一个MVC项目启动后,首先访问的地址是http://localhost:xxx/Home/Index,这时候我们也明白因为在程序中有个叫做Home的控制器,并且在这个控制器下面有个叫做Index的方法,基于这种对应的关系,才有了这种结果,那么这种对应关系是如何产生,如何工作的了?

在我们网站在第一次启动的时候,会去访问一个全局的配置文件Global.asax下面的Application_Start()方法,代码如下

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing; namespace Test
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}

在这个方法中就注册了我们的路由配置,相关的注册文件都是在在App_Start目录下

路由配置文件RouteConfig.cs,内容如下

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing; namespace Test
{
public class RouteConfig
{
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 }
);
}
}
}

首先是忽略路由,满足匹配会被忽略,如果没有特殊需求,这个地方就不需要更改,

name表示路由的名称,同一个路由集合中,路由名称必须唯一,不能够有重名,

url就是正则表达式,用于http://localhost:xxx/后路径地址的匹配,

defaults表示缺省路由,也就是默认的路由.这是一个路由规则增删的方法,并且默认的路由为home/index,

还有一个比较常用的参数是constraints,用于条件约束,简单实例如下:

     public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //假若Home下有Test(int year,int month,int day)方法
//home/Test_2017_06_05可以访问至该方法
//home/Test_2017_6_05是无法访问
routes.MapRoute(
name: "Constraints",
url: "{controller}/{action}_{year}_{month}_{day}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
//条件参数,约束后面参数(此处简单正则:4位数字,2位数字,2位数字)
constraints: new { year = @"^\d{4}", month = @"^\d{2}", day = @"^\d{2}" }); routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
}

路由浅析

那么路由究竟是如何工作的,下面是2个与路由工作十分紧密的2个方法的源码,任何http请求进入后,都会先被它们处理

 public virtual void PostResolveRequestCache(HttpContextBase context)
{
RouteData routeData = RouteCollection.GetRouteData(context);
if (routeData != null)
{
IRouteHandler routeHandler = routeData.RouteHandler;
if (routeHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler")));
}
if (!(routeHandler is StopRoutingHandler))
{
RequestContext requestContext = new RequestContext(context, routeData);
context.Request.RequestContext = requestContext;
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)
{
UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
return;
}
throw new HttpException(, SR.GetString("Assess_Denied_Description3"));
}
context.RemapHandler(httpHandler);
}
}
}

PostResolveRequestCache

 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 == )
{
return null;
}
bool flag = false;
bool flag2 = false;
if (!RouteExistingFiles)
{
flag = IsRouteToExistingFile(httpContext);
flag2 = true;
if (flag)
{
return null;
}
}
using (GetReadLock())
{
foreach (RouteBase item in this)
{
RouteData routeData = item.GetRouteData(httpContext);
if (routeData != null)
{
if (!item.RouteExistingFiles)
{
if (!flag2)
{
flag = IsRouteToExistingFile(httpContext);
flag2 = true;
}
if (flag)
{
return null;
}
}
return routeData;
}
}
}
return null;
}

GetRouteData

大致分析下这段源码,我们可以得出下列比较重要的结论

1在路由匹配之前,先一步检查了物理文件的存在,所以mvc和webform可以共存,如果存在满足路径条件的aspx文件,它会优先被访问

2路由是从上到下逐个匹配的,所以排列的顺序对于路由匹配是非常重要的

路由扩展

在上述基础下,我们对路由有了大概的了解,对此我们可以简单扩展一下

路由并不是只能够在路径规则上做文章,我们也可以继承路由的基类RouteBase自定义一些路由,然后把自定义的路由放入注册路由集合中,调准好顺序,实现我们想要的结果.因为能够得到HttpContext这个用户请求的上下文,我们可以完成很多扩展,例如检查ip,浏览器类型,参数等等,下面我们就简单的实现不同浏览器访问到不同路径的功能,如下:

     public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //注意顺序
routes.Add("Agent",new Agent()); routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
} }
public class Agent : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
if (httpContext.Request.UserAgent.Contains("Chrome/63.0.3239.132"))
{
var data = new RouteData(this, new MvcRouteHandler());
data.Values.Add("controller", "Home");
data.Values.Add("action", "About");
return data;
}
else
{
return null;
}
} public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return null;
}
}

一定得注意路由排列的顺序,如果将上面的Agent路由放在Default路由后面,那么就直接会访问到Home/Index,而不会去判断.

我们也可以通过自定义继承了RouteBase的Route类,来完成特殊路径的扩展,如下

   public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.Add(new Route("Test",new TestRouteHandler())); routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
} public class TestRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new TestHandler();
}
}
public class TestHandler : IHttpHandler
{
public bool IsReusable => true; public void ProcessRequest(HttpContext context)
{
context.Response.Write("Test");
}
}

效果如下:

出自:博客园-半路独行

原文地址:https://www.cnblogs.com/banluduxing/p/9185159.html

本文出自于http://www.cnblogs.com/banluduxing 转载请注明出处。

.Net MVC5路由机制与扩展的更多相关文章

  1. MVC5路由系统机制详细讲解

    请求一个ASP.NET mvc的网站和以前的web form是有区别的,ASP.NET MVC框架内部给我们提供了路由机制,当IIS接受到一个请求时,会先看是否请求了一个静态资源(.html,css, ...

  2. ASP.NET MVC5路由系统机制详细讲解

    请求一个ASP.NET mvc的网站和以前的web form是有区别的,ASP.NET MVC框架内部给我们提供了路由机制,当IIS接受到一个请求时,会先看是否请求了一个静态资源(.html,css, ...

  3. MVC5之路由机制

    ---恢复内容开始--- MVC是一种模式,是基于asp.net上的一种设计.路由机制不属于MVC,路由机制属于asp.net.因此,mvc的路由机制就是基于asp.net路由机制上的一种“自定制”. ...

  4. typecho路由机制详解

    本文介绍的是typecho的路由机制,引自 不烦恼路由机制是typecho的核心,有很多功能都是基于路由功能设计的,理解并熟悉TE的路由机制将非常有助于插件的开发. 完整的路由表如下: array ( ...

  5. asp.net MVC 路由机制

    1:ASP.NET的路由机制主要有两种用途: -->1:匹配请求的Url,将这些请求映射到控制器 -->2:选择一个匹配的路由,构造出一个Url 2:ASP.NET路由机制与URL重写的区 ...

  6. asp.net MVC 路由机制 Route

    1:ASP.NET的路由机制主要有两种用途: -->1:匹配请求的Url,将这些请求映射到控制器 -->2:选择一个匹配的路由,构造出一个Url 2:ASP.NET路由机制与URL重写的区 ...

  7. MVC路由机制(转)

    今天我来缕一下MVC的路由机制,因为使用MVC已经快一年了,之前也只是上手,没有系统去理会.项目完了,结合实际使用,回过头来深入一下. MVC 学习索引(点击即可) 一个请求进入IIS后 传统ASP. ...

  8. 【C#】 WebApi 路由机制剖析

    C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转自:https://blog.csdn.net/wulex/article/details/71601478 2017年05月11日 10 ...

  9. C#进阶系列——WebApi 路由机制剖析:你准备好了吗?

    前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分. 它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home/Index,那么你只需要配置一个默认路由就能简单搞定: ...

随机推荐

  1. yii mailer 扩展发送邮件

    // 将mailer扩张放到 yii 的extension目录下 $message = 'Hello World!'; $mailer = Yii::createComponent('applicat ...

  2. .NET和UNITY版本问题

    亲测:unity5.5之前:通过VS工程属性查看.NET版本为3.5, 对应unity中没有可查看的项,只有一个Api Compatibility level 是.net subset2.0,看名字, ...

  3. 2015年传智播客JavaEE 第168期就业班视频教程day45-ERP项目-01 10-类图结构分析设计

    运行astah-pro.bat,这是windows下运行的.astah-run.sh是Linux下运行的. 类结构视图的作用是描述类模型和模型与模型之间的关系,也就是说我们在这要把这个一对多和多对多的 ...

  4. Socket、RPC通信实例,简单版本,仅供查阅

    TCP/IP Socket 如果使用TCP协议来传递数据,客户端和服务器端需要分别经过以下步骤: server: 创建socket对象 - bind(绑定socket到指定地址和端口) - liste ...

  5. js高级——构造函数,实例对象和原型对象——prototype、__proto__和constructor构造器

    一.前言 了解JavaScript面向对象,需要先了解三个名词: 构造函数,实例对象和原型对象. 注意:JavaScript中没有类(class)的概念,取而代之的是构造函数,两者类似却又有很大的差别 ...

  6. METAL渲染是什么?

    METAL渲染是什么? Metal渲染是由苹果公司为iOS8以及更新版本开发的全新的底层渲染API.它侧重于减少GPU驱动的工作量,从而当Metal调用时,CPU的消耗将降至最低.这样一来,游戏就可以 ...

  7. 微信H5支付常见问题汇总

    常见问题 一.回调页面 正常流程用户支付完成后会返回至发起支付的页面,如需返回至指定页面,则可以在MWEB_URL后拼接上redirect_url参数,来指定回调页面. 如,您希望用户支付完成后跳转至 ...

  8. 可跨平台C++开源图形图像框架:openFrameworks

    博客参考:https://www.hahack.com/codes/openframeworks-intro/#%E4%BB%80%E4%B9%88%E6%98%AF-openframeworks 和 ...

  9. CentOS7.2部署KVM虚拟机

    转自:http://www.linuxidc.com/Linux/2017-01/140007.htm 学习了关于PostGis.OSM数据以及Mapnik相关内容,接下来将利用假期重点学习Postg ...

  10. 【原创】请避免GO语言中的携程空跑(CPU突然激增)

    其实GO语言从1.6版本开始非常不错了,GC性能优化非常到位,并且各种并行设计比从新实现一套C++版本的确是方便不少. 语言包也很多,库也相对稳定,完全可以适用于生产环境. 本文主要是给刚刚入门新手注 ...