ASP.NET MVC系列:UrlRouting

1. URLRouting简介

    URL(Uniform Resource Locator),统一资源定位器,是用于完整描述Internet上的网页或其他资源地址的一种标识方法。

  URL一般可以由6部分组成,格式如下:

protocol :// hostname [:port] [/path] [?parameters] [#fragment]

  URL各部分说明:

  protocol 协议:可以是HTTP(超文本传输协议)、FTP(文件传输协议)和HTTPS(安全超文本传输协议)。

  hostname 主机名:指在互联网中存放资源的服务器DNS主机名或IP地址。

  port 端口号:该选项是一个小于66536的正整数,是各服务器或协议约定的通信端口。

  path 路径:用来表示一个Web站点中的目录或文件资源的地址。

  parameters 参数列表:参数形式为以=隔开的键/值对,多个参数之间用&连接。

  fragment 信息片段:用于直接定位到页面中的某个锚点标记。

2. URLRouting与URLRewrite区别

  URLRouting是一组从URL到请求处理程序间的映射规则,将URL映射到能够处理业务需求的Action上。URLRouting是一个独立的类库System.Web.Routing.dll。

  URLRouting为将URL映射到Controller的Action上,处理流程图如下:

  URLRewrite为将URL映射到具体的文件资源上,处理流程图如下:

3. ASP.NET MVC中使用及自定义URLRouting规则

  在Web.config文件中与Routing有关的的节点:sytem.web.httpModules,system.web.httpHandlers,system.webserver.modules,system.webserver.handlers。

  ASP.NET MVC应用程序第一次启动时,将调用Global.asax中Application_Start()方法。每个ASP.NET MVC应用程序至少需要定义一个URLRouting来指明应用程序如何处理请求,复杂的应用程序可以包含多个URLRouting。

3.1 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 Libing.Portal.Web
{
    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 }
            );
        }
    }
}
复制代码

  Global.asax

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Libing.Portal.Web
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}
复制代码

3.2 Route类

  RouteCollection对象以静态属性的方式声明在RouteTable的属性Routes中,RouteCollection对象存储的是Route类的实例。一个完整的Route类实例需要有URL、默认值、约束、数据密钥及路由处理程序等属性。

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; }

3.3 Route类属性

  name:
  路由名称,必须是唯一不能重复。

  url:
  在Route类中,属性URL是一个字符串,用于描述请求中URL的格式。该字符串可能不完全是一个实际的URL,可以带一些{}标记的占位符,使用占位符可以从URL中提取数据。如:

"{controller}/{action}/{id}"

  {controller}参数的值用于实例化一个处理请求的控制类对象,{action}参数的值用于指明处理当前请求将调用控制器中的方法。

  defaults:

new { controller = "Home", action = "Index", id = UrlParameter.Optional }

  constraints:

new { controller = @"^\w+", action = @"^\w+", id = @"\d+" }

  namespaces:

  Route.DataTokens属性,获取或设置传递到路由处理程序但未用于确定该路由是否匹配 URL 模式的自定义值。

3.4 自定义URLRouting规则

  分页:

复制代码
routes.MapRoute(
"Page",
"{controller}/List/Page/{page}",
new { controller = "Home", action = "List", page = UrlParameter.Optional },
new { page = @"\d*" }
);
复制代码
public string List(int? page)
{
return page == null ? "1" : page.ToString();
}

  本地化多语言Routing:

复制代码
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    // 本地化
    routes.MapRoute(
        name: "Localization",
        url: "{lang}/{controller}/{action}/{id}",
        defaults: new { lang = "zh-CN", controller = "Home", action = "Index", id = UrlParameter.Optional },
        constraints: new { lang = "^[a-zA-Z]{2}(-[a-zA-Z]{2})?$" }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}
复制代码

  分页Routing:

复制代码
routes.MapRoute(
    name: "PagedList",
    url: "{controller}/Page/{page}",
    defaults: new { controller = "Product", action = "Index" },
    constraints: new { page = @"\d+" }
);
复制代码

  Blog根据日期Routing:

复制代码
routes.MapRoute(
    name: "blog",
    url: "blog/{user}/{year}/{month}/{day}",
    //defaults: new { controller = "Blog", action = "Index", day = 1 },
    defaults: new RouteValueDictionary{
        {"controller", "Blog"},
        {"action", "Index"},
        {"day", 1}
    },
    constraints: new { year = @"\d{4}", month = @"\d{1,2}", day = @"\d{1,2}" }
);
复制代码

  Reports根据年月Routing:

复制代码
routes.MapRoute(
    name: "Reports",
    url: "Reports/{year}/{month}",
    defaults: new { controller = "Reports", action = "Index" },
    constraints: new { year = @"\d{4}", month = @"\d{1,2}" }
);
复制代码

3.5 创建Routing约束

  使用正则表达式来指定路由约束:

复制代码
routes.MapRoute(
    name: "Product",
    url: "Product/{ProductID}",
    defaults: new { controller = "Product", action = "Details" },
    constraints: new { ProductID = @"\d+" }
);
复制代码

3.6 自定义Routing约束

  通过实现IRouteConstraint接口来实现自定义路由。

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Web.Routing;

namespace Libing.Portal.Web.Models.Constraints
{
    public class LocalhostConstraint : IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext,
            Route route,
            string parameterName,
            RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            return httpContext.Request.IsLocal;
        }
    }
}
复制代码
复制代码
routes.MapRoute(
    name: "Admin",
    url: "Admin/{action}",
    defaults: new { controller = "Admin" },
    constraints: new { isLocal = new LocalhostConstraint() }
);
复制代码

  自定义浏览器访问Routing约束:

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Web.Routing;

namespace Libing.Portal.Web.Models.Constraints
{
    public class UserAgentConstraint:IRouteConstraint
    {
        private string _userAgent;

        public UserAgentConstraint(string userAgent)
        {
            _userAgent = userAgent;
        }

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            return httpContext.Request.UserAgent != null && httpContext.Request.UserAgent.Contains(_userAgent);
        }
    }
}
复制代码
复制代码
routes.MapRoute(
    name: "Chrome",
    url: "{*catchall}",
    defaults: new { controller = "Home", action = "Index" },
    constraints: new { customConstraint = new UserAgentConstraint("Chrome") }
);
复制代码

  自定义用户个人网址Routing:

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Web.Routing;

using Libing.Portal.Web.Models;

namespace Libing.Portal.Web.Models.Constraints
{
    public class UserConstraint : IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            using (PortalContext context = new PortalContext())
            {
                string userRouteValue = values["user"].ToString();

                var user = (from u in context.Users
                            where u.UserName == userRouteValue
                            select u).FirstOrDefault();

                return user != null;
            }
        }
    }
}
复制代码
复制代码
routes.MapRoute(
    name: "User",
    url: "{user}/{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    constraints: new { isValidUser = new UserConstraint() }
);
复制代码

4. 使用RouteDebugger调试URLRouting

  RouteDebugger为一个独立的类库,RouteDebug.dll,可以从网上下载到,使用方法如下:

  1>. 添加对RouteDebug引用;

  2>. Global.ascx修改

复制代码
 using RouteDebug;

protected void Application_Start()
{
  AreaRegistration.RegisterAllAreas();

  RegisterGlobalFilters(GlobalFilters.Filters);
  RegisterRoutes(RouteTable.Routes);

  RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes); // 添加RouteDebug
}

请求一个ASP.NET  mvc的网站和以前的web form是有区别的,ASP.NET MVC框架内部给我们提供了路由机制,当IIS接受到一个请求时,会先看是否请求了一个静态资源(.html,css,js,图片等),这一步是web form和mvc都是一样的,如果不是则说明是请求的是一个动态页面,就会走asp.net的管道,mvc的程序请求都会走路由系统,会映射到一个Controller对应的Action方法,而web form请求动态页面是会查找本地实际存在一个aspx文件。下面通过一个ASP.NET MVC5项目来详细介绍一下APS.NET MVC5路由系统的机制。

一、认识Global.asax.cs

当我们创建一个APS.NET MVC5的项目的时候会在项目的根目录中生成一个Global.asax文件。
 
  1. public class MvcApplication : System.Web.HttpApplication
  2. {
  3. protected void Application_Start()
  4. {
  5. //注册 ASP.NET MVC 应用程序中的所有区域
  6. AreaRegistration.RegisterAllAreas();
  7. //注册 全局的Filters
  8. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  9. //注册 路由规则
  10. RouteConfig.RegisterRoutes(RouteTable.Routes);
  11. //注册 打包绑定(js,css等)
  12. BundleConfig.RegisterBundles(BundleTable.Bundles);
  13. }
  14. }

这个Application_Start方法会在网站启动的自动调用,其中我们看到:RouteConfig.RegisterRoutes(RouteTable.Routes);这个就是向ASP.NET MVC 框架注册我们自定义的路由规则,让之后的URL能够对应到具体的Action。接下来我们再来看看RegisterRoutes方法做了些什么?
 
  1. public class RouteConfig
  2. {
  3. public static void RegisterRoutes(RouteCollection routes)
  4. {
  5. routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  6. routes.MapRoute(
  7. name: "Default",
  8. url: "{controller}/{action}/{id}",
  9. defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  10. );
  11. }
  12. }

上面代码是vs自动为你们生成,只定义了一个默认规则。
1、规则名:Default
2、URL分段:{controller}/{action}/{id},分别有三段,第一段对应controller参数,第段为action参数,第三段为id参数
3、URL段的默认值:controller为Home,action为Index,id = UrlParameter.Optional表示该参数为可选的。
之所以我们访问http://www.xx.com/ 这样的URL网址能正确返回,是因为我们设置了URL段的默认值,相当于访问:
http://www.xx.com/Home/Index

RegisterRoutes调用的是RouteCollection的MapRoute方法,RouteCollection是一个集合,继承于Collection<RouteBase>


三、ASP.NET MVC默认的命名约定

1、Controller命名约定

Controller类必须以Controller结尾,比如:HomeController,ProductController。我们在页面上用HTML heper来引用一个Controller的时只需要前面Home,Product就可以,ASP.NET MVC框架自带的DefaultControllerFactory自动为我们在结尾加上Controller,并开始根据这个名字开始找对应的类。我们创建一个ASP.NET MVC项目新加的Controller,文件会自动放在根目录的Controllers文件夹里面,我们刚开始可以看到有一个HomeController.cs。当然你也可以实现接口IControllerFactory,定义自己的ControllerFactory来改变查找Controller文件的行为。我会再以后的文章中介绍。

2、View命名约定

ASP.NET MVC的视图View默认情况是放在根目录的Views文件下的,规则是这样的:/Views/ControllerName/ActionName.cshtml。比如:HomeController的Action名字为Index的视图对应文件为:/Views/Home/Index.cshtml
因此是通过Controller和Action的名字来确定视图文件的位置的。采用这个命名约定的好处是在Action返回视图的时候会MVC框架会按照这个约定找到默认的视图文件。比如在ProductController的Action方法List最后是这样的代码:
return View();
会自动去路径,/Views/Product/找文件List.cshtml(或者List.aspx如果使用的老的视图引擎)。
当然也可以指定视图的名字:
return View("~/Views/Product/List.cshtml")
或者
return View("MyOtherView")

MVC框架在查找具体的默认视图文件时,如果在/Views/ControllerName/下面没有找到,会再在/Views/Shared下面找,如果都没找到就会找错:找不到视图。

四、ASP.NET MVC的URL规则说明

最开始我们在网站的Application_Start事件中注册一些路由规则routes.MapRoute,当有请求过来的时候,mvc框架会用这些路由规则去匹配,一旦找到了符合要求就去处理这个URL。例如有下面这个URL:
http://mysite.com/Admin/Index
URL可以分为几段,除去主机头和url查询参数,MVC框架是通过/来把URL分隔成几段的。上面的URl分为两段。如下图:

第一段的值为Admin,第二段的值为Index,我们是很容易看出Admin对应就是Controller,Index就是Action。但是我们要告诉MVC框架这样的规则,因此为下面的Application_Start有下面的代码:
 
 
  1. routes.MapRoute(
  2. name: "Default",
  3. url: "{controller}/{action}/{id}",
  4. defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
  5. );

上面表示URL规则是:
{controller}/{action} 
这个路由规则有两个段,第一个是controller,第二个是action。声明url段每个部分要且{}括起来,相当于占位符,是变量。
当一个URL请求到来的时候MVC路由系统就负责把它匹配到一个具体的路由规则,并把URL每段的值提取出来。这里说“一个具体的路由规则”,是因为可能会注册多个路由规则,MVC路由系统会根据注册顺序一个一个的查找匹配,直到到为止。
默认情况,URL路由规则只匹配与之有相同URL段数量的URL。如下表:
URL
URL段
http://mysite.com/Admin/Index
controller = Admin
action = Index 
http://mysite.com/Index/Admin
controller = Index
action = Admin 
http://mysite.com/Apples/Oranges
controller = Apples
action = Oranges
http://mysite.com/Admin
无匹配-段的数量不够
http://mysite.com/Admin/Index/Soccer
无匹配-段的数量超了

五、mvc创建一个简单的Route规则

我们在前面注册路由规则都是通过下面的方式:
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}");
  3. }

用到了RouteCollection的MapRoute方法。其实我们还可以调用 Add方法,传一个Route的实例给它一样的达到相同的效果。
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler());
  3. routes.Add("MyRoute", myRoute);
  4. }

六、mvc路由的默认值的设定

之前有说:URL路由规则只匹配与之有相同URL段数量的URL,这种是严格,但是我们又想有些段不用输入,让用户进入指定的页面。像,http://www.xx.com/Home/就是进入进入Home的Index。只需要设定mvc路由的默认值就可以了。
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" });
  3. }

要设置Controller和Action的默认值。
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}",
  3. new { controller = "Home", action = "Index" });
  4. }

下面是一个具体的Url对应的Route映射。
Url段的数量
实例
Route映射
0
mydomain.com 
controller = Home
action = Index 
1
mydomain.com/Customer
controller = Customer
action = Index 
2
mydomain.com/Customer/List
controller = Customer
action = List 
3
mydomain.com/Customer/List/All
无匹配—Url段过多 

七、mvc使用静态URL段

前面定义路由规则都是占位符的形式,{controller}/{action},我们也可以使用在使用静态字符串。如:
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}",
  3. new { controller = "Home", action = "Index" });
  4. routes.MapRoute("", "Public/{controller}/{action}",
  5. new { controller = "Home", action = "Index" });
  6. }

上面匹配:http://mydomain.com/Public/Home/Index
路由:"Public/{controller}/{action}"只匹配有三段的url,第一段必须为Public,第二和第三可以是任何值,分别用于controller和action。
除此这外,路由规则中可以既包含静态和变量的混合URL段,如:
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("", "X{controller}/{action}");
  3. routes.MapRoute("MyRoute", "{controller}/{action}",
  4. new { controller = "Home", action = "Index" });
  5. routes.MapRoute("", "Public/{controller}/{action}",
  6. new { controller = "Home", action = "Index" });
  7. }

八、mvc的路由中自定义参数变量

mvc框架除了可以定义自带的controller和action的参数之外,还可以定义自带的变量。如下:
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
  3. new { controller = "Home", action = "Index", id = "1" });
  4. }

上面定义了一个id,默认值我们设为1。
这个路由可以匹配0-3个url段的url,第三个url段将被用于id。如果没有对应的url段,将应用设置的的默认值。
自定义参数变量使用:
方法一、
 
  1. public ViewResult CustomVariable() {
  2. ViewBag.CustomVariable = RouteData.Values["id"];
  3. return View();
  4. }

MVC框架从URL获取到变量的值都可以通过RouteData.Values["xx"],这个集合访问。
方法二、
public ViewResult CustomVariable(int id) {
 
ViewBag.CustomVariable = id;
    return View();
}
MVC框架使用内置的Model绑定系统将从URL获取到变量的值转换成Action参数相应类型的值。这种转换除了可以转换成基本int,string等等之外还可以处理复杂类型,自定义的Model,List集合等。相关参考: MVC中默认Model Binder绑定Action参数为List、Dictionary等集合的实例

九、mvc定义可选URL段、可选参数

asp.net mvc定义 参数是也可以设置为可选的,这样用户可以不用输入这部分的参数。

1、注册路由时定义可选URL段

public static void RegisterRoutes(RouteCollection routes) {
 
    routes.MapRoute("MyRoute", "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}

2、通过Action参数来定义可选参数

public ViewResult CustomVariable(string id = "DefaultId") {
 
ViewBag.CustomVariable = id;
    return View();
通过Action参数来定义可选参数是没有加默认值的,而通过注册路由时定义可选URL段是加了默认值的,是利用c#参数的默认参数特性。这样如果用户没有输入这部分url段,就会默认值就会被使用。

十、mvc使用*来定义变长数量的URL段

除了在路由规则中声明固定的数量的URL段,我们也可以定义变长数量的URL段,如下面代码:
public static void RegisterRoutes(RouteCollection routes) {
 
    routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
通过变量前面加一个星号(*)开头就能匹配任意变长数量的URL。
匹配URL如下:
Url段的数量
实例
Route映射
0
mydomain.com 
controller = Home
action = Index 
1
mydomain.com/Customer
controller = Customer
action = Index 
2
mydomain.com/Customer/List
controller = Customer
action = List 
3
mydomain.com/Customer/List/All
controller = Customer
action = List
id = All 
4
mydomain.com/Customer/List/All/Delete
controller = Customer
action = List
id = All
catchall = Delete  
5
mydomain.com/Customer/List/All/Delete/Perm
controller = Customer
action = List
id = All
catchall = Delete /Perm

十一、mvc使用命名空间来为路由的Controller类定优先级

当一个用户输入一个URL请求ASP.NET MVC的网站时,ASP.NET MVC会根据URL的获取请求是找到是哪一个Controller类,如果一个项目有多相同的类名的Controller,就会有问题。比如:当请求的变量controller的值为Home时,MVC框架就会去找一个Controller名字为HomeController的类,这个类(HomeController)默认是不受限制的,如果多个命名空间都有名字为HomeContoller的类, ASP.NET MVC就不知道怎么办了。当这种情况发生是,就会报错:
“/”应用程序中的服务器错误。
找到多个与名为“Home”的控制器匹配的类型。如果为此请求(“{controller}/{action}/{id}”)提供服务的路由没有指定命名空间以搜索与此请求相匹配的控制器,则会发生这种情况。如果是这样,请通过调用带有 'namespaces' 参数的 "MapRoute" 方法的重载来注册此路由。
“Home”请求找到下列匹配的控制器:
WebApplication1.Controllers.HomeController
WebApplication1.Controllers1.HomeController 

[InvalidOperationException: 找到多个与名为“Home”的控制器匹配的类型。如果为此请求(“{controller}/{action}/{id}”)提供服务的路由没有指定命名空间以搜索与此请求相匹配的控制器,则会发生这种情况。如果是这样,请通过调用带有 'namespaces' 参数的 "MapRoute" 方法的重载来注册此路由。
“Home”请求找到下列匹配的控制器:
解决办法:
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("Default",
  3. "{controller}/{action}/{id}",
  4. new { controller = "Home", action = "Index", id = UrlParameter.Optional },
  5. new string[] { "WebApplication1.Controllers" }
  6. );
  7. }

上面MapRoute的最后一个参数,new string[] { "WebApplication1.Controllers" }就是指定先去命名空间为WebApplication1.Controllers查找在controller,如果找到就停止往下找,没找到还是会去其它命名空间中去找的。因此当你指定的这个命名空间如果没存在要找的controller类,而在其它命名空间是有的,是会正常执行的,所以这里指定命名空间并不是限定了命名空间,而只是设了一个优先级而已。

十二、mvc定义路由规则的约束

在前面我们介绍了为mvc路由的规则设置路由默认值和可选参数,现在我们再深入一点,我们要约束一下路由规则。

1、用正则表达式限制asp.net mvc路由规则

 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
  3. new { controller = "Home", action = "Index", id = UrlParameter.Optional },
  4. new { controller = "^H.*"},
  5. new[] { "URLsAndRoutes.Controllers"});
  6. }

上面用到正则表达式来限制asp.net mvc路由规则,表示只匹配contorller名字以H开头的URL。

2、把asp.net mvc路由规则限制到到具体的值

 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
  3. new { controller = "Home", action = "Index", id = UrlParameter.Optional },
  4. new { controller = "^H.*", action = "^Index$|^About$"},
  5. new[] { "URLsAndRoutes.Controllers"});
  6. }

上例在controller和action上都定义了约束,约束是同时起作用是,也就是要同时满足。上面表示只匹配contorller名字以H开头的URL,且action变量的值为Index或者为About的URL。

3、把asp.net mvc路由规则限制到到提交请求方式(POST、GET)

 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
  3. new { controller = "Home", action = "Index", id = UrlParameter.Optional },
  4. new { controller = "^H.*", action = "Index|About",
  5. httpMethod = new HttpMethodConstraint("GET") },
  6. new[] { "URLsAndRoutes.Controllers" });
  7. }
上面表示只匹配为GET方式的请求。

4、使用接口IRouteConstraint自定义一个asp.net mvc路由约束

下面我自定义一个约束对特定浏览器进行处理。
UserAgentConstraint.cs:
 
  1. using System.Web;
  2. using System.Web.Routing;
  3. namespace URLsAndRoutes.Infrastructure {
  4. public class UserAgentConstraint : IRouteConstraint {
  5. private string requiredUserAgent;
  6. public UserAgentConstraint(string agentParam) {
  7. requiredUserAgent = agentParam;
  8. }
  9. public bool Match(HttpContextBase httpContext, Route route, string parameterName,
  10. RouteValueDictionary values, RouteDirection routeDirection) {
  11. return httpContext.Request.UserAgent != null &&
  12. httpContext.Request.UserAgent.Contains(requiredUserAgent);
  13. }
  14. }
  15. }

asp.net mvc自定义路由约束的使用:
 
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
  3. new { controller = "Home", action = "Index", id = UrlParameter.Optional },
  4. new {
  5. controller = "^H.*", action = "Index|About",
  6. httpMethod = new HttpMethodConstraint("GET", "POST"),
  7. customConstraint = new UserAgentConstraint("IE")
  8. },
  9. new[] { "URLsAndRoutes.Controllers" });
  10. }
上面表示这个路由规则只匹配用户使用IE浏览器的请求。利用这点我们就可以实现不同浏览器使用不同的Controller,进行不同的处理。虽然这样做的意义不大,但是不排除有时会有这种变态的需求。

十三、mvc将URL路由到磁盘文件

mvc的网站并不是所以的url请求都是对应controller,action,我们仍然要一种方式来提供一些静态内容,比如:html文件,css,图片,javascript文件些,其实默认情况下mvc框架在在收到url请求时会先判断这个url是否是对应一个磁盘中真实存在的文件,如果是直接返回,这时路由是没有使用到的,如果不是真实存在的文件时才会走路由系统,再去匹配注册的路由规则。
这种默认的处理url机制顺序我们也可以改变它,让在检查物理文件之前就应用路由,如下:
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.RouteExistingFiles = true;
  3. routes.MapRoute("DiskFile", "Content/StaticContent.html",
  4. new {
  5. controller = "Account", action = "LogOn",
  6. },
  7. new {
  8. customConstraint = new UserAgentConstraint("IE")
  9. });
  10. routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
  11. new { controller = "Home", action = "Index", id = UrlParameter.Optional },
  12. new {
  13. controller = "^H.*", action = "Index|About",
  14. httpMethod = new HttpMethodConstraint("GET", "POST"),
  15. customConstraint = new UserAgentConstraint("IE")
  16. },
  17. new[] { "URLsAndRoutes.Controllers" });
  18. }


我们把RouteExistingFiles属性设置为true,表示存在的文件也走路由,上面我们把Content/StaticContent.html这个文件映射到controller 为Account,action 为LogOn中了,而并不是指磁盘中存在的文件。基于asp.net mvc的这个特性我们就可以实现mvc以.html结尾的伪静态,具体实现方式请看我以前写的文章: 教你如何在asp.net mvc中实现高性能以html结尾的伪静态

十四、mvc跳过、绕开路由系统设定

上面我们用使用routes.RouteExistingFiles = true,让所有的请求都走路由系统过一下,难免有一些性能影响,因为一些图片,一些真正的html,文件是没有必要的。我们可以对些文件做一些起特殊设定让它们跳过、绕开路由系统。下面就是让Content目录下的所有文件都绕开mvc的路由系统:
 
  1. public static void RegisterRoutes(RouteCollection routes) {
  2. routes.RouteExistingFiles = true;
  3. routes.MapRoute("DiskFile", "Content1/StaticContent.html",
  4. new {
  5. controller = "Account", action = "LogOn",
  6. },
  7. new {
  8. customConstraint = new UserAgentConstraint("IE")
  9. });
  10. routes.IgnoreRoute("Content/*{filename}");
  11. routes.MapRoute("", "{controller}/{action}");
  12. }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苍狼_2001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值