新建一个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 转载请注明出处。

最新文章

  1. JAVA 入门第二章 (面对对象)
  2. MyBatis源码分析(3)—— Cache接口以及实现
  3. Python
  4. 设置Windows 7 防火墙端口规则
  5. mac安装Mysql官方示例数据库employee
  6. saltstack之(二)软件包下载安装
  7. Oracle错误:ORA-01033
  8. 99. Recover Binary Search Tree
  9. 站点下的GridView的RowCommand事件的设置,与站点应用不一样
  10. Entity Framework 重写OnModelCreating,控制生成表名的单复数
  11. python 画正弦曲线
  12. (函数封装)domReady
  13. 针对数据量较大的表,需要进行跨库复制,采用navcat 实现sqlite数据库跨数据库的数据表迁移 [转载]
  14. 摄像头ov2685中关于sensor id 设置的相关的寄存器地址
  15. vue-cli 第二章 (常见问题修正)
  16. spring cloud 学习
  17. jquery checkbox checked 却不显示对勾
  18. layui透明弹框
  19. GridFS Example
  20. C# 后台动态添加标签(span,div) 以及模板添加

热门文章

  1. (1/24) 认识webpack
  2. leetcode917
  3. ADO Connection failure
  4. html 1.0 鼠标放上去会亮 onmouseover onmouseout 以及this标签的使用
  5. c++经典排序算法全集(转)
  6. Xcode 中设置部分文件ARC支持
  7. JS nodeJs 的日期计算
  8. 02-SSH综合案例:需求分析(后台)
  9. rabbitmq 和Spring 集成 实现(一)
  10. springMVC框架的作用