.Net MVC5路由机制与扩展
新建一个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路由机制与扩展的更多相关文章
- MVC5路由系统机制详细讲解
请求一个ASP.NET mvc的网站和以前的web form是有区别的,ASP.NET MVC框架内部给我们提供了路由机制,当IIS接受到一个请求时,会先看是否请求了一个静态资源(.html,css, ...
- ASP.NET MVC5路由系统机制详细讲解
请求一个ASP.NET mvc的网站和以前的web form是有区别的,ASP.NET MVC框架内部给我们提供了路由机制,当IIS接受到一个请求时,会先看是否请求了一个静态资源(.html,css, ...
- MVC5之路由机制
---恢复内容开始--- MVC是一种模式,是基于asp.net上的一种设计.路由机制不属于MVC,路由机制属于asp.net.因此,mvc的路由机制就是基于asp.net路由机制上的一种“自定制”. ...
- typecho路由机制详解
本文介绍的是typecho的路由机制,引自 不烦恼路由机制是typecho的核心,有很多功能都是基于路由功能设计的,理解并熟悉TE的路由机制将非常有助于插件的开发. 完整的路由表如下: array ( ...
- asp.net MVC 路由机制
1:ASP.NET的路由机制主要有两种用途: -->1:匹配请求的Url,将这些请求映射到控制器 -->2:选择一个匹配的路由,构造出一个Url 2:ASP.NET路由机制与URL重写的区 ...
- asp.net MVC 路由机制 Route
1:ASP.NET的路由机制主要有两种用途: -->1:匹配请求的Url,将这些请求映射到控制器 -->2:选择一个匹配的路由,构造出一个Url 2:ASP.NET路由机制与URL重写的区 ...
- MVC路由机制(转)
今天我来缕一下MVC的路由机制,因为使用MVC已经快一年了,之前也只是上手,没有系统去理会.项目完了,结合实际使用,回过头来深入一下. MVC 学习索引(点击即可) 一个请求进入IIS后 传统ASP. ...
- 【C#】 WebApi 路由机制剖析
C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转自:https://blog.csdn.net/wulex/article/details/71601478 2017年05月11日 10 ...
- C#进阶系列——WebApi 路由机制剖析:你准备好了吗?
前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分. 它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home/Index,那么你只需要配置一个默认路由就能简单搞定: ...
随机推荐
- css踩过的坑
1. 英文内容会撑破容器而中文内容是可以自动换行的 原因: 因为数学规则因素,中文韩文朝鲜文等可以在任何字之后断行的,而英文却不能把一个单词拆开换行,只能撑破容器 解决: 用word-break: b ...
- 使用JdbcTemplate访问数据库
参考源端:https://blog.csdn.net/liaodehong/article/details/76974827 今天用Spring Boot访问一下数据库,并且把数据返回到页面中,进行增 ...
- python的with用法(参考)
一.With语句是什么? 有一些任务,可能事先需要设置,事后做清理工作.对于这种场景,Python的with语句提供了一种非常方便的处理方式.一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中 ...
- Day15-Django
all_entries = Entry.objects.all() #查询所有 Entry.objects.filter(pub_date__year=2006) #查询所有pub_date为2006 ...
- 七、配置ssh keys连通github跟ssh-agent
jenkins+github配置完成后,能够实现在提交pull request或者直接push时,能够将提交的代码拉去一份到服务器本地,并自动merge:但是代码拉去下来了,部署环境的时候却需要输入登 ...
- Django学习---信号
Django学习之信号 如果我想对所有在数据库创建数据的时候记录一条日志. 比如我们在django中往数据库中增加一条数据,希望生成一条操作日志,或者在数据保存和数据保存之后都保存一条操作日志,那我们 ...
- Spring MVC 学习 之 - URL参数传递
在学习 Spring Mvc 过程中,有必要来先了解几个关键参数: @Controller: 在类上注解,则此类将编程一个控制器,在项目启动 Spring 将自动扫描此类,并进行对应URL路由映 ...
- delphi Firemonkey ListView 使用参考
delphi Firemonkey ListView 使用参考 Tokyo版本 http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Customizin ...
- 14 并发编程-(协程)-greenlet模块&gevent模块
1.实现多个任务之间进行切换,yield.greenlet都没有实现检测I/O,greenlet在实现多任务切换下更简单 from greenlet import greenlet def eat(n ...
- MD5 几种方法的选择
转:http://zoroeye.iteye.com/blog/2026984?utm_source=tuicool&utm_medium=referral md5加密实现方法有很多种,也导致 ...