精通ASP.NET MVC ——路由

本文章将关注定义路由,并使用它们去处理URL,使用户能够到达控制器和动作。

文章非常长,可以对路由机制有较初步的了解。首先创建示例项目,项目名为UrlAndRoutes,如下图所示:

 

然后是创建示例控制器和示例视图,有三个控制器,分别为Admin控制器,Home控制器,Customer控制器,一个命名为ActionName示例视图。这三个控制器都返回ActionName视图。代码如下图所示:

namespace UrlsAndRoutes.Controllers
{public class AdminController : Controller{// GET: Adminpublic ActionResult Index(){ViewBag.Controller = "Admin";ViewBag.Action = "Index";return View("ActionName");}}
}

 

namespace UrlsAndRoutes.Controllers
{public class HomeController : Controller{// GET: Homepublic ActionResult Index(){ViewBag.Controller = "Home";ViewBag.Action = "Index";return View("ActionName");}}
}
namespace UrlsAndRoutes.Controllers
{public class CustomerController : Controller{// GET: Customerpublic ActionResult Index(){ViewBag.Controller = "Customer";ViewBag.Action = "Index";return View("ActionName");}public ActionResult List(){ViewBag.Controller = "Customer";ViewBag.Action = "List";return View("ActionName");}}
}

ActionName.cshtml视图的代码很简单,就是返回调用它的control和ActionName的名称,如下图所示:


@{Layout = null;
}<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>ActionName</title>
</head>
<body><div> the control is @ViewBag.Controller</div><div> the action is @ViewBag.Action</div>
</body>
</html>

测试示例代码,启动默认路由,显示页面没有问题,如下图所示:

               

 


URL模式简介 

路由系统由一组路由来实现它的功能。这些路由共同组成了应用程序的URL架构。这种URL架构是应用程序能够识别并能对之做出响应的一组URL。

URL可以分成几个片段。除主机名和查询字符串之外,这些URL的组成部分都用"/"字符进行分割,如下所示:

第一个片段含有单词“Admin”,第二个片段含有单词“Index”。很显然,第一个片段和控制器有关,第二个片段和动作有关。以下是做这件事的一个URL模式:{ controller } / { action } 

当处理一个输入请求时,路由系统的工作是将这个请求URL与一个模式进行匹配,然后从此URL为这个模式中定义的片段变量提取出相应的值。片段变量用花括号 “ { ” 和 “ } ”字符表示。上述示例模式有两个片段变量,其名称分别为“controller”和“action”,因此,controller片段的值是Admin,而action片段的值是Index。

所谓“与一个模式”匹配是指,一个MVC应用程序通常会有几条路由,而路由系统会把输入URL逐一与每条路由的URL模式相比较,直到能找到一条匹配的路由为止。

默认情况下,一个URL模式将匹配具有正确片段的的任何URL。例如,模式{controller} / {action}将匹配任何具有两个片段的URL,如下图所示:

URL匹配
请求URL片段变量
http://mysite.com/Admin/Indexcontroller = Admin  action = Index
http://mysite.com/Index/Admincontroller = Index  action = Admin
http://mysite.com/Apples/Orangecontroller = Apples action = Orange
http://mystie.com/Admin不匹配,片段太少
http://mysite/Admin/Index/Soccer不匹配,片段太多

 

上图突出了URL模式的两个关键行为:

1、URL模式是保守的,因此只匹配与模式具有相同片段的URL。你可以从表中第四个,第五个例子看到这种情况(片段数不同就是不匹配)。

2、URL模式是宽松的,如果一个URL正好是具有正确的片段数,该模式就用来为片段变量提取值,而不管这个值是什么。

 

 创建并注册一条简单路由

路由是在RouteConfig.cs文件中进行定义的,该文件位于项目的App_start文件夹中。 代码如下图所示:

namespace UrlsAndRoutes
{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 });}}
}

先删掉上图中RegisterRoutes方法中其他代码,以便更加关注重点,如下图所示:

namespace UrlsAndRoutes
{public class RouteConfig{public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute","{controller}/{action}");}}
}

运行代码,可以看到如下报错界面: 

但是如果导航到一个与{controller} / {action } 匹配的URL时,将看到正确显示。如下图,就导航到了/Home/Index:

         

 

定义默认值 

当请求应用程序的默认值时,出现错误的原因是它不匹配已经定义的路由。前面说过,URL是保守的,他们只匹配指定片段的URL。改变这种行为的一个方式是使用默认值。修改RegisterRoutes方法如下图所示:

namespace UrlsAndRoutes
{public class RouteConfig{public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute","{controller}/{action}",new { action = "Index"});}}
}

上述代码中为action片段提供了一个默认值,该路由也将匹配单片段URL。当处理单片段URL时,路由系统将从唯一的URL片段中提取controller的值,并对action变量使用默认值。于是,可以请求http://localhost:29802/home ,系统会自动调用home控制器上的Index动作方法。运行效果如下图所示:

             

当然,也可以更直接一点,对controller也赋默认值,代码如下图所示: 

namespace UrlsAndRoutes
{public class RouteConfig{public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute","{controller}/{action}",new {controller = "home", action = "Index"});}}
}

这就是为什么刚新建了一个项目,没有任何片段 就导航到home控制器下的Index动作的原因,因为RegisterRoute方法里默认控制器是home,动作是Index,运行效果如下图所示:

              

 使用静态URL片段

 并不是一个URL模式中的所有片段都需要是可变的。也可以创建具有静态片段的模式。假设希望匹配一下这种URL,以支持带有public前缀的URL:http://localhost:29802/Public/Home/Index 可以通过修改如下代码来实现这个效果:

    public class RouteConfig{public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute","public/{controller}/{action}",new {controller = "home", action = "Index"});}}

这个全新的URL模式将只匹配含有三个片段的URL,第一个必须是public,其他两个片段含有任何值,并将被用于controller和action变量。如果省略后两个片段,那么将使用默认值。 运行效果如下图所示:

                     


 

 还可以创建既有静态变量也有可变元素片段的URL模式,如下图代码所示:

        public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("", "X{controller}/{action}");//第一条路由routes.MapRoute("MyRoute","public/{controller}/{action}",//第二条路由new {controller = "home", action = "Index"});}

第一条路由的模式是匹配任意两个片段URL,而第一个片段是以“X”打头。用于controller的值取自第一个片段除“X”以外的部分,Action的值取自第二个片段。如果启动程序并到导航到  /XHome/Index ,可以看到如下图所示:

注意:路由系统根据最先定义的路由模式来匹配一个输入URL,并且只有在不匹配的时候,才会继续对下一条路由进行处理。路由依次被尝试,直到找出匹配的一条,或这组路由被尝试完。所以,必须首先定义教具体的路由。如果将上图中两条路由改变定义的顺序,那么X{controller}这条路由将永远无法到达,路由系统回去找 名为“XHome” 的控制器,因为这个控制器是不存在的,所以会报404——未找到的错误。


可以结合静态变量片段和默认值为特定的路由创建一个别名。如果已经公开发布了URL方案,而且它与你的用户形成了一种契约,那么,创建这种别名可能是有用的。如果在这种情况下(指已经于用户形成契约)重构应用程序,则需要保留以前的URL格式。设想以前用的是一个Shop控制器,现在要有Home控制器来代替。修改代码,下图演示了如何才能创建一个保留旧式URL方案的路由。

        public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("ShopSchem","Shop/{action}",  //新增路由new { controller = "Home" });routes.MapRoute("", "X{controller}/{action}");routes.MapRoute("MyRoute","public/{controller}/{action}",new {controller = "home", action = "Index"});}

添加这条路由匹配第一个片段是“Shop”的任意两片段URL,action的值取自第二个URL片段。这个URL模式不含controller的可变片段,因而会使用所提供的默认值。这意味着对Shop控制器上一个动作请求会被转换成Home控制器的请求,启动程序,并导航到/Shop/Index 网址。如下图所示:

而且可以更进一步,被重构且不再出现在控制器中的动作方法创建别名,为此,只要简单的创建一个静态URL,并提供controller和action的默认值,如下图所示:

        {routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("ShopSchem2", "Shop/OldAction",  //新增路由new { controller = "Home",action = "Index"});routes.MapRoute("ShopSchem","Shop/{action}", new { controller = "Home" });routes.MapRoute("", "X{controller}/{action}");routes.MapRoute("MyRoute","public/{controller}/{action}",new {controller = "home", action = "Index"});}

再一次提醒,要注意放置新路由的位置,以使它被首先定义。这是因为新路由比后面的路由更具体。例如,如果一个对Shop/OldAction 的请求被下一条路由定义来处理,就会得到与想要的不同的结果。这个请求将被处理成一个“404——未找到”错误,并注意,路由名称必须唯一。运行结果,如下图所示:

                  

定义自定义片段变量 

contorller和action片段变量对MVC框架而言有特殊的含义,显然,它们对应于请求进行服务的控制器和动作方法。 但是也可以自己定义变量。修改代码如下图所示:

        public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute", "{controller}/{action}/{id}",new { controller = "Home",action = "Index",id = "DefaultId"});}

该路由的URL模式定义了标准的controller 和 action 变量,以及一个名为“id”的自定义变量。这条路由将匹配任何0~3个片段的URL。第三个片段的内容将被赋值给id变量,而且如果没有第三个片段,将采用默认值。 

通过使用RouteData.Values属性,能够在一个动作方法中访问任何一个片段变量。如下图所示,对Home控制器添加了以一个名为“CustomVariable”的动作方法:

namespace UrlsAndRoutes.Controllers
{public class HomeController : Controller{// GET: Homepublic ActionResult Index(){ViewBag.Controller = "Home";ViewBag.Action = "Index";return View("ActionName");}public ActionResult CustomVariable(){ViewBag.Controller = "Home";ViewBag.Action = "CustomVariable";ViewBag.CustomVariable = RouteData.Values["id"];return View();}}
}

并添加CustomVariable.cshtml视图与之匹配,代码如下图所示: 

@{Layout = null;
}<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>CustomVariable</title>
</head>
<body><div> The controller is : @ViewBag.Controller</div><div> The action is @ViewBag.Action</div><div> The custom varibale is @ViewBag.CustomVariable</div>
</body>
</html>

运行程序,并导航到 /Home/CustomVariable/Hello 网址,结果如下图所示:

        

          以为给变量id提供了一个默认值DefaultId,所以导航到  /Home/CustomVariable 网址,结果如下图所示:

         

用自定义变量作为动作方法参数 

使用RouteData.Values属性只是访问自定义路由变量的一种方式。另一种方式要优雅的多。如果以URL模式中的变量相匹配的名称,来定义动作方法的参数,MVC框架将把从URL获得的值作为参数传递给该动作方法。 代码如下图所示:

namespace UrlsAndRoutes.Controllers
{public class HomeController : Controller{// GET: Homepublic ActionResult Index(){ViewBag.Controller = "Home";ViewBag.Action = "Index";return View("ActionName");}public ActionResult CustomVariable(string id){ViewBag.Controller = "Home";ViewBag.Action = "CustomVariable";ViewBag.CustomVariable = id;return View();}}
}

当路由系统根据上图所定义的路由来匹配一个URL时,URL中第三个片段的值被赋值给了自定义变量id。MVC框架会将片段变量列表与动作方法参数列表进行比较,如果名称匹配,便将URL的值传递给该方法。 

 这里将id参数定义成一个string,但MVC框架会尝试将URL的值转化为所定义的任何参数类型,如果将id参数声明为int 或者 DateTime,那么,从URL模式接收到的将是一个被解析成该类型示例的值。

 

定义可选URL片段

 可选URL片段是指,用户不需要指定,但又未指定默认值的片段。通过将默认值设置为“UrlParameter.Optional”,便指明了一个片段变量是可选的,如下图所示:

    public class RouteConfig{public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute", "{controller}/{action}/{id}",new { controller = "Home", action = "Index", id = UrlParameter.Optional});}}

以上的路由将匹配不管是否提供id的URL,下表演示了它对不同URL的工作方式: 

匹配带有可选片段变量的URL
片段示例URL映射成
0mydomain.comcontroller = Home  action = Index
1mydomain.com/Customercontroller = Customer action = Index
2mydomain.com/Customer/Listcontroller = Customer action = List
3mydomain.com/Customer/List/Allcontroller = Customer action = List id = All
4mydomain.com/Customer/List/All/Delete不匹配,片段太多

由上表可见,只有当输入URL中存在相应片段时,id变量才会被添加到变量集合中。 在下图代码中,对控制器做了修改,以相应无对应值的id片段变量。

namespace UrlsAndRoutes.Controllers
{public class HomeController : Controller{// GET: Homepublic ActionResult Index(){ViewBag.Controller = "Home";ViewBag.Action = "Index";return View("ActionName");}public ActionResult CustomVariable(string id){ViewBag.Controller = "Home";ViewBag.Action = "CustomVariable";ViewBag.CustomVariable = id ?? "<no value>";return View();}}
}

运行效果如下图所示: 


使用可选URL片段强制关注分离

如果开发人员十分注重MVC模式中的关注分离,他们不喜欢将片段变量的默认值放在应用程序的路由中。如果是因为这样,可以使用C#中的可选参数,以及路由中的可选片段变量,来定义动作方法的参数的默认值。 

    public class HomeController : Controller{// GET: Homepublic ActionResult Index(){ViewBag.Controller = "Home";ViewBag.Action = "Index";return View("ActionName");}public ActionResult CustomVariable(string id = "DefaultId")//可选参数{ViewBag.Controller = "Home";ViewBag.Action = "CustomVariable";ViewBag.CustomVariable = id;return View();}}

以上代码和下面的路由是等价的: 

routes.MapRoute("MyRoute", "{controller}/{action}/{id}",new { controller = "Home", action = "Index", id = "DefaultId" });

定义可变长路由

改变URL模式默认保守性的另一种方式是接收可变数目的URL片段。这让你能够以一个单一的路由,对任意长度的URL进行路由。通过指定一个叫做“全匹配(catch)”的片段变量,并以星号(*)作为其前缀,便可以定义对可变片段数的支持。代码如下图所示:

    public class RouteConfig{public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional });}}

 现在,这条路由将匹配任何URL,无论URL包含多少个片段数,也不管这些片段的值是什么。前三个片段分别用于设置controller、action和id变量的值。如果URL含有更多的片段,则它们全部被赋给catchall 变量。如下图所示:

匹配带有catchall片段变量的URL
片段数示例URL映射成
0/controller = Home action = Index
1/Customercontroller = Customer action = Index
2/Customer/Listcontroller = Customer action = List
3/Customer/List/Allcontroller = Customer action = List id = All
4/Customer/List/All/Deletecontroller = Customer action = List id = All catchall = Delete
5/Customer/List/All/Delete/Permcontroller = Customer action = List id = All catchall = Delete/Perm

以上路由中的URL模式所匹配的片段数量是没有上限的。注意:有catchall捕获的片段是以“片段/片段/片段”的形式表示的。你要对这个字符串进行处理,把它分解为一个个片段。 


按命名空间区分控制器优先顺序

当一个输入请求URL与一条路由进行匹配时,MVC框架取得controller变量的值,并查找相应的控制器的名称。例如,当controller变量名称是“Home”时,那么,MVC框架会查找名称为“HomeController”的控制器。这是一个不合格的类名,如果两个或者多个名为“HomeController”的控制器,MVC框架将不知道怎么做。

为了测试,在项目的根目录下创建一个名为AdditionalControllers的文件夹,并添加一个Home控制器,如下图所示:

namespace UrlsAndRoutes.AdditionalControllers
{public class HomeController : Controller{// GET: Homepublic ActionResult Index(){ViewBag.Controller = "Additional Controllers  --- Home";ViewBag.Action = "Index";return View("ActionName");}}
}

运行程序,会发现报了如下错误: 

很明显可以看到是错误提示是控制器重复了,这个问题比想象的更会经常出现,尤其是在一些大的MVC项目中, 遇到命名冲突只是时间问题。为了解决这一问题,可以告诉MVC框架,在试图解析控制器名称的时候,对某些命名空间给予优先处理,如下图所示:

namespace UrlsAndRoutes
{public class RouteConfig{public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional},new[] { "UrlsAndRoutes.AdditionalControllers" });}}
}

上述代码中把命名空间表示成一个字符串数组,告诉MVC框架,在考察其他命名空间之前,先考察UrlsAndRoutes.AdditionalControllers 命名空间。

如果在这个命名空间中找不到合适控制器,那么MVC框架会默认回到正常行为,并考察所有可用的命名空间。 运行结果如下图所示:

               

注意:添加到一条路由的命名空间具有同等的优先级,MVC框架不会先检查第一命名空间,然后第二、第三命名空间。也就是说,同一个条路由中的命名空间不是按顺序进行检查的,而是会被同等对待的。如下图中,如果把两个项目的命名空间都加到这条路由里来,还是会报错:

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional},
new[] { "UrlsAndRoutes.AdditionalControllers" , "UrlsAndRoutes.Controllers" });

如果希望对一个命名空间的某个控制器给与优先级,但是又要解析另一个命名空间中的所有其他控制器,就需要创建多条路由,如下图所示:

routes.MapRoute("AddControllerRoute", "Home/{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 
new[] { "UrlsAndRoutes.AdditionalControllers" });routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional},
new[] { "UrlsAndRoutes.Controllers"});

当用户明确的请求一个片段为Home的URL时,会运用第一条路由,并且会以AdditionalControllers文件夹中的Home控制器为目标。所有的其他请求,包括未指定第一片段的那些请求,会以controllers文件夹中的控制器去处理。 

也可以告诉MVC框架,只考察指定的命名空间。如果找不到一个匹配的控制器,那么框架不会搜索其他地方。代码如下所示:

Route myRoute = routes.MapRoute("AddControllerRoute", "Home/{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, 
new[] { "UrlsAndRoutes.AdditionalControllers" });myRoute.DataTokens["UseNamespaecFallback"] = false;//禁止搜索其他命名空间

 

用则表达式约束路由 

    public class RouteConfig{public static void RegisterRoutes(RouteCollection routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",new { controller = "Home", action = "Index", id = UrlParameter.Optional},new { controller = "^C.*"},new[] { "UrlsAndRoutes.Controllers"});}}

 以上代码用正则表达式形成了一个约束,它只匹配controller变量值已“C”字母的大头的URL。

默认值是是在约束检查之前运用的,因此,如果请求的URL是“/”,会将以默认值“Home”运用于controller,然后才会检查约束。而且,如果此时controller的值是以“C”,则会报错,如下图所示:

如果把约束改成以H开头,则运行正常: 

            

将一条路由约束到一组指定的值 

可以用正则表达式来约束一条路由,以便对于一个URL片段,只有指定的一些值才能形成匹配。可以用竖线“|”字符来做这件事。代码如下图所示:

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional},
new { controller = "^H.*",action = "^Index$|^About$"},
new[] { "UrlsAndRoutes.Controllers"});

上面这条约束将允许这条路由值匹配 action 片段的值是 “Index” 或 “About”的URL,controller的值必须是H打头。 

 

 使用HTTP方法约束路由

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional},
new { controller = "^H.*",action = "^Index$|^About$",
httpMethod = new HttpMethodConstraint("GET","POST")},//限制请求类型
new[] { "UrlsAndRoutes.Controllers"});

上述代码将这条路由限制到GET和POST请求。 

使用类型和值约束 

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional},
new { controller = "^H.*",action = "^Index$|^About$",
httpMethod = new HttpMethodConstraint("GET","POST"),
id = new RangeRouteConstraint(10,20)},//值约束
new[] { "UrlsAndRoutes.Controllers"});

在System.Web.Mvc.Routing.Constraints 命名空间的约束类中,检查片段变量是否是不同的C#类型值,并执行基本的检查。在上图中,使用了RangeRouteConstraint类,它检查提供给片段的变量的值是在两个边界之间的一个有效的int类型。下图描述了完整的约束集合。他们并不接受参数,由于它们将用于配置路由,所以仅显示类名,暂且忽略了属性约束列。

路由属性类
名称描述属性约束
AlphaRouteConstraint()匹配字母字符 主要是(A~Z,a~z)alpha
BoolRouteConstraint()匹配一个可以解析成bool类型的值bool
DateTimeRouteConstraint()匹配一个可以解析成DateTime类型的值datetime
DecimalRouteConstraint()匹配一个可以解析成deciaml类型的值decimal
DoubleRouteConstraint()匹配一个可以解析成double类型的值double
FloatRouteConstraint()匹配一个可以解析成float类型的值float
IntRouteConstraint()匹配一个可以解析成int类型的值int

LengthRouteConstraint(len)

LengthRouteConstraint(min,max)

匹配一个指定字符个数的值,或匹配字符个数在min和max之间的值length(len)     length(min,max)
LongRouteConstraint()匹配一个可以解析成long类型的值long
MaxRouteConstraint(val)匹配一个值小于val的int值max(val)
MaxLengthRouteConstraint(len)匹配一个长度不超过len的字符值maxlength(len)
MinRouteConstraint(val)匹配一个值大于val的int值min(val)
MinLengthRouteConstraint(len)匹配一个长度至少为len字符串minlength(len)
RangeRouteConstraint(min,max)匹配一个值在min和max之间的值range(min,max)

 使用CompoundRouteConstraint类,该类接受一个约束数组作为它构造器的参数,可以为一个单一的片段变量组合不同的约束。如下图所示,同时将AlphaRouteConstraint 和 MinLengthRouteConstraint运用到id片段变量,以确保路由将仅匹配包含字母字符并且至少含有6个字符的字符串值:

routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional},
new { controller = "^H.*",action = "^Index$|^About$",
httpMethod = new HttpMethodConstraint("GET","POST"),
id = new CompoundRouteConstraint( 
new IRouteConstraint[] {new AlphaRouteConstraint(),
new MinLengthRouteConstraint(6) })},
new[] { "UrlsAndRoutes.Controllers"});

定义自定义约束 

 如果标准约束不满足你的需求,可以通过实现IRouteConstraint接口,来定义自己的自定义约束。在示例项目中添加一个Infrastructrue文件夹,并创建新的类UserAgentConstrainst.cs,如下所示:

namespace UrlsAndRoutes.Infrastructure
{public class UserAgentConstraint:IRouteConstraint{private string requiredUserAgent;public UserAgentConstraint(string agentParam){this.requiredUserAgent = agentParam;}public bool Match(HttpContextBase httpContext,Route route,String parameterName,RouteValueDictionary values,RouteDirection routeDirection){return httpContext.Request.UserAgent != null && httpContext.Request.UserAgent.Contains(requiredUserAgent);}}
}

IRouteConstraint 接口定义了 Match方法,它的实现可以用来对路由系统指示它的约束是否已经得到满足。Match方法的参数提供了对以下对象的访问:客户端请求,待评估路由,约束的参数名,从URL提取的片段变量,以及该请求要检查的是输入URL还是输入的URL的细节。对于上述示例,要检查的是客户端请求的UserAgent属性的值,看它是否含有一个被传递给构造器的值。

namespace UrlsAndRoutes.Infrastructure
{public class UserAgentConstraint:IRouteConstraint{private string requiredUserAgent;public UserAgentConstraint(string agentParam){this.requiredUserAgent = agentParam;}public bool Match(HttpContextBase httpContext,Route route,String parameterName,RouteValueDictionary values,RouteDirection routeDirection){return httpContext.Request.UserAgent != null && httpContext.Request.UserAgent.Contains(requiredUserAgent);}}
}

并增加一条路由:

routes.MapRoute("ChromeRoute", "{*catchall}", 
new { controller = "Home", action = "Index" }, 
new { customConstraint = new UserAgentConstraint("Chrome") },
new[] { "UrlsAndRoutes.AdditionalControllers" });routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional},
new { controller = "^H.*",action = "^Index$|^About$",
httpMethod = new HttpMethodConstraint("GET"),
id = new CompoundRouteConstraint( 
new IRouteConstraint[] {
new AlphaRouteConstraint(),
new MinLengthRouteConstraint(6) })},
new[] { "UrlsAndRoutes.Controllers"});

第一条路由使他之匹配来自用户代理字符串含有Chrome的浏览器的请求,并指向UrlsAndRoutes.AdditionalControllers。该路由是有一个片段,意味着controller 和 action 总是取自默认值,而不是URL本身。 

第二条路由将匹配其他所有请求,并以controller文件夹中的控制器为目标,这两条路由的情况是,有一种浏览器最终只能访问程序的同一个位置。第二条路由动用了约束,第三个片段只能包含6个或者以上的字母字符,以使第二个路由匹配。运行结果如下图所示:

     

   

 

 

 

 

 

 

 

 

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/548550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET Web API简单学习

Web API 简介 Web API可以返回 json、xml类型的数据&#xff0c;对于数据的增删改查&#xff0c;提供了对应的资源操作&#xff0c;按照要求的类型进行处理&#xff0c;主要包括&#xff1a;Get&#xff08;查&#xff09;&#xff0c;Post&#xff08;增&#xff09;&#xff…

利用NCO 3.0 调用SAP中的函数

简介 .Net Connector 3.0&#xff0c;简称 Nco3.0。Nco3.0 是 SAP 针对 .net 平台提供的编程接口&#xff0c;由 Nco1.0/Nco2.0 演变而来。如果使用 .net 平台编程&#xff0c;推荐使用 NCo3.0。3.0 版与之前1.0/2.0 版本比较&#xff0c;不管是 API 还是架构&#xff0c;都重新…

char与varchar区别(MYISAM)

Char属于固定长度的字符类型&#xff0c;而varchar属于可变长的字符类型。 下表将各种字符串值保存到char(4)和varchar&#xff08;4&#xff09;列后的结果&#xff0c;说明了char和varchar之间的差别 值 Char(4) 存储需求 Varchar (4) 存储需求 ‘’ ‘ ’ 4字符节…

Win10系统局域网中的其他电脑能Ping通但是无法访问本地IIS发布的网站

局域网中的其他电脑无法访问本地IIS发布的网站&#xff0c;但是能ping通&#xff0c;基本是由于没开放端口的原因。 打开防火墙 —— 高级设置&#xff1a; 点击“入站规则”&#xff0c;然后是“新建规则”&#xff1a; 然后选择“端口” &#xff1a; 选择“TCP”&#xff0c…

C#调试WebService

简单调试 1、首先&#xff0c;新建一个WebService项目用于测试&#xff0c;如下图所示&#xff1a; 2、项目会默认生成一个Hello方法&#xff0c;但是由于Hello方法太简单&#xff0c;添加一个Add方法用于计算两个整数之和&#xff0c;如下图所示&#xff1a; [WebMethod]publ…

ArchLinux学习之环境变量

2019独角兽企业重金招聘Python工程师标准>>> 使得刚修改的环境变量生效&#xff1a;source <带环境变量的文件> 查看环境变量&#xff1a; env 或 set 持久化的环境变量主要存在于这几个文件中&#xff1a; /etc/profile/etc/environment~/.bash_profile~/.b…

精通ASP.NET MVC ——属性路由

在上一篇文章中&#xff0c;有约定路由的介绍。MVC 5中增加了对属性路由这一新技术的支持。在属性路由中&#xff0c;路由是由直接运用于控制器的C#属性定义的。 启动和运用属性路由 默认情况下属性路由是禁止的&#xff0c;通过MapMvcAttributeRoutes扩展方法可以启用它。该…

ASP.NET MVC 阻止通过URL访问服务器上的静态资源文件

背景 在默认情况下&#xff0c;MVC框架是支持对服务器静态资源的访问的&#xff0c;我们在项目根目录下新建一个Content文件夹&#xff0c;然后添加一个命名为“StaticContent.html”的html文件&#xff0c;如下图所示&#xff1a; StaticContent.html中的代码如下图所示&…

精通ASP.NET MVC——控制器和动作

在MVC框架中&#xff0c;控制器必须实现System.Web.Mvc命名空间的IController接口&#xff0c;如下图所示&#xff1a; //// 摘要:// 定义控制器所需的方法。public interface IController{//// 摘要:// 执行指定的请求上下文。//// 参数:// requestContext:// 请…

精通ASP.NET MVC ——视图

文章非常长&#xff0c;仅仅用于记录自己学习。 创建自定义视图引擎 创建自定义视图引擎的价值是&#xff0c;演示请求处理管道如何工作&#xff0c;并完善关于MVC架构如何操作的知识&#xff0c;视图引擎实现IViewEngine接口&#xff0c;如下图所示&#xff1a; public inte…

使用列表选择框控件

本例使用列表选择框控件,并向其中添加删除列表项&#xff0c;程序运行如下图所示。 程序代码如下。 using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; namespace eg38_checklistBoxApp {public partial class Form1 : Form…

精通ASP.NET MVC ——辅助器方法

辅助器方法(Helper Method)&#xff0c;其作用是对代码块和标记进行打包&#xff0c;以便能够在整个MVC框架应用程序中重用。 首先新建一个项目&#xff0c;添加一个Home控制器&#xff0c;如下图所示&#xff1a; public class HomeController : Controller{// GET: Homepubli…

精通ASP.NET MVC ——模型绑定

模型绑定&#xff08;Model Binding&#xff09;是指&#xff0c;用浏览器以Http请求方式发送的数据来创建.Net对象的过程。 准备示例项目 新建一个空的MVC项目&#xff0c;名叫MvcModels&#xff0c;接下去会以此项目来演示各种功能。 在Models文件夹中创建一个Person.cs类…

精通ASP.NET MVC ——模型验证

文章内容较长&#xff0c;用于记录自己学习。模型验证&#xff08;Model Vaildation&#xff09;是确保应用程序所接受的数据适合于绑定到模型&#xff0c;并且在不合适时给用户提供有用的信息&#xff0c;以帮助他们修正问题的过程。 准备示例项目 新建一个空的MVC项目&…

[wbia 2.2] 对检索结果进行评估

评估对检索系统的性能&#xff1a; 由于我们这里的检索结果&#xff0c;是主要根据PageRank的排名&#xff0c;以及Lucene对文本的分词和相关性计算的最后得分&#xff0c;进行权值调整后得到的排名结果。 这里对我们检索系统的进行性能评估&#xff0c;这里主要评估的是检索结…

错误175:具有固定名称MySql.Data.MySqlClient的ADO.NET提供程序未在计算机或者应用程序配置文件中注册或者无法加载

背景&#xff1a; EF连接MySQL时报错&#xff0c;截图如下图所示&#xff1a; 网上翻阅了很多资料&#xff0c;感觉有一篇文章说的比较靠谱&#xff1a;点击阅读。解决问题的大致过程如下&#xff1a; 在尝试使用MySQL&#xff0c;ADO.NET&#xff08;数据库优先&#xff09;和…

精通ASP.NET MVC ——URL和Ajax辅助器方法

Ajax(或者&#xff0c;如果你愿意&#xff0c;也可以称为AJAX)是 Asynchronous JavaScripts and XML(异步JavaScripts与XML)。其XML部分并不如它往常那样意义重大&#xff0c;但是异步部分却使AJax十分有用。这是后台请求服务器数据&#xff0c;而不必重载Web页面的一种模型。M…

精通ASP.NET MVC ——控制器可扩展性

MVC中引导动作方法执行过程的请求流程管道中&#xff0c;有两个重要的部件&#xff1a;控制器工厂(Controller Factory) 和 动作调用器&#xff08;Action Invoker&#xff09;。控制器工厂负责创建对请求进行服务的控制器实例&#xff0c;动作调用器负责查找并调用控制器类中的…

永中向香港博览会主办方演示云办公(转载)

4月16号“香港国际资讯博览会”主办方香港贸发局对永中云办公产品非常感兴趣&#xff0c;由永中员工演示&#xff0c;并拍摄了演示视频。转载于:https://blog.51cto.com/premium/837675

Backbone.js学习笔记

为什么80%的码农都做不了架构师&#xff1f;>>> http://documentcloud.github.com/backbone var todoItem new TodoItem(); todoItem.url /todo; todoItem.fetch(); todoItem.get(description)var TodoItem Backbone.Model.extend({urlRoot: /todos }); var tod…