当前位置: 移动技术网 > IT编程>开发语言>.net > [Asp.net MVC]Asp.net MVC5系列——Routing特性

[Asp.net MVC]Asp.net MVC5系列——Routing特性

2018年03月21日  | 移动技术网IT编程  | 我要评论

欢乐喜剧人 第二季,多线程技术,加护亚依qvod

ASP.NET MVC 5支持一种新的路由协议,称为路由特性。顾名思义,路由特性使用特性来定义路径。路由特性使你的Web应用程序URI有了更多的控制。当然,MVC5也支持以前定义路由的方式,你可以在一个项目中混合使用这两种方式来定义路由。

 

路由特性

例如,一个电子商务网站可能有以下的路由规则:

 

{productId:int}/{productTitle} 

Mapped to ProductsController.Show(int id)

{username} 

Mapped to ProfilesController.Show(string username)

{username}/catalogs/{catalogId:int}/{catalogTitle} 

Mapped to CatalogsController.Show(string username, int catalogId)

以往的ASP.NET MVC版本,该规则将设置在routeconfig.cs文件中,并指出实际控制器的Action方法,如:

 

1 routes.MapRoute(

2     name: "ProductPage",

3     url: "{productId}/{productTitle}",

4     defaults: new { controller = "Products", action = "Show" },

5     constraints: new { productId = "\\d+" }

6 );

当路由的定义与Action方法,在同一个源文件中而不是在外部配置类中声明,它可以更容易的处理URI和行动之间的映射的。以前的路径定义将使用以下,简单的特性就可以达到目的:

 

1 [Route("{productId:int}/{productTitle}")]

2 public ActionResult Show(int productId) { ... }

使用路由特性

首先得启用Attribute路由,我们可以调用MapMvcAttributeRoutes方法来启用Attribute路由:

 

复制代码

1 public class RouteConfig

2 {

3     public static void RegisterRoutes(RouteCollection routes)

4     {

5         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

6  

7         routes.MapMvcAttributeRoutes();

8     }

9 }

复制代码

也可以和常规的路由设置一起使用。

 

复制代码

 1 public static void RegisterRoutes(RouteCollection routes)

 2 {

 3     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 4  

 5     routes.MapMvcAttributeRoutes();

 6  

 7     routes.MapRoute(

 8         name: "Default",

 9         url: "{controller}/{action}/{id}",

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

11     );

12 }

复制代码

可选URI参数和参数的默认值

可以通过添加“?”标记一个参数为可选的参数,也可以为表单参数设置默认值(参数=value)。

 

复制代码

 1 public class BooksController : Controller

 2 {

 3     // eg: /books

 4     // eg: /books/1430210079

 5     [Route("books/{isbn?}")]

 6     public ActionResult View(string isbn)

 7     {

 8         if (!String.IsNullOrEmpty(isbn))

 9         {

10             return View("OneBook", GetBook(isbn));

11         }

12         return View("AllBooks", GetBooks());

13     }

14  

15     // eg: /books/lang

16     // eg: /books/lang/en

17     // eg: /books/lang/he

18     [Route("books/lang/{lang=en}")]

19     public ActionResult ViewByLanguage(string lang)

20     {

21         return View("OneBook", GetBooksByLanguage(lang));

22     }

23 }

复制代码

在上面的例子中,/books和/books/1430210079将路由到View方法,前者将返回所有书的列表信息,后者将返回特定的书的信息。/books/lang和/books/lang/en将采用同样的方式。

 

路由前缀

在同一个控制器里面,路由以相同的前缀开始,例如:

 

复制代码

 1 public class ReviewsController : Controller

 2 {

 3     // eg: /reviews

 4     [Route("reviews")]

 5     public ActionResult Index() { ... }

 6     // eg: /reviews/5

 7     [Route("reviews/{reviewId}")]

 8     public ActionResult Show(int reviewId) { ... }

 9     // eg: /reviews/5/edit

10     [Route("reviews/{reviewId}/edit")]

11     public ActionResult Edit(int reviewId) { ... }

12 }

复制代码

你可以通过使用[routeprefix ]特性整个控制器设定一个共同的前缀:

 

复制代码

 1 [RoutePrefix("reviews")]

 2 public class ReviewsController : Controller

 3 {

 4     // eg.: /reviews

 5     [Route]

 6     public ActionResult Index() { ... }

 7     // eg.: /reviews/5

 8     [Route("{reviewId}")]

 9     public ActionResult Show(int reviewId) { ... }

10     // eg.: /reviews/5/edit

11     [Route("{reviewId}/edit")]

12     public ActionResult Edit(int reviewId) { ... }

13 }

复制代码

如果需要定义不同的路由前缀,可以在方法特性上使用波浪号~覆盖原来的前缀,例如:

 

复制代码

1 [RoutePrefix("reviews")]

2 public class ReviewsController : Controller

3 {

4     // eg.: /spotlight-review

5     [Route("~/spotlight-review")]

6     public ActionResult ShowSpotlight() { ... }

7  

8     ...

9 }

复制代码

默认路由

你也可以运用在控制器级别的[路径]特性,将Action方法作为一个参数。该路由将被应用在控制器中的所有Action方法,除非Action方法使用了一个具体的[路由]特性,否则将使用控制器级别的默认路由。

 

复制代码

 1 [RoutePrefix("promotions")]

 2 [Route("{action=index}")]

 3 public class ReviewsController : Controller

 4 {

 5     // eg.: /promotions

 6     public ActionResult Index() { ... }

 7  

 8     // eg.: /promotions/archive

 9     public ActionResult Archive() { ... }

10  

11     // eg.: /promotions/new

12     public ActionResult New() { ... }

13  

14     // eg.: /promotions/edit/5

15     [Route("edit/{promoId:int}")]

16     public ActionResult Edit(int promoId) { ... }

17 }

复制代码

由上可知,Action方法的路由特性的优先级大于控制器路由特性的优先级。

 

路由约束

路由约束,使你限制路由模版中的参数是如何匹配的,一般的语法为{parameter:constraint},例如:

 

复制代码

1 // eg: /users/5

2 [Route("users/{id:int}"]

3 public ActionResult GetUserById(int id) { ... }

4  

5 // eg: users/ken

6 [Route("users/{name}"]

7 public ActionResult GetUserByName(string name) { ... }

复制代码

这里,如果id为int类型,将选择第一个路由,否则选择第二个路由。

 

下表列出了支持的约束:

 

 

 

注意,其中一些带min的约束,可以带参数。

 

你也可以在一个参数上应用多个约束,多个约束以分号";"分割,例如:

 

1 // eg: /users/5

2 // but not /users/10000000000 because it is larger than int.MaxValue,

3 // and not /users/0 because of the min(1) constraint.

4 [Route("users/{id:int:min(1)}")]

5 public ActionResult GetUserById(int id) { ... }

通过问号"?"可以在内联约束中指定可选参数,例如:

 

1 // eg: /greetings/bye

2 // and /greetings because of the Optional modifier,

3 // but not /greetings/see-you-tomorrow because of the maxlength(3) constraint.

4 [Route("greetings/{message:maxlength(3)?}")]

5 public ActionResult Greet(string message) { ... }

自定义路由约束

可以通过实现接口IRouteConstraint 自定义路由约束,例如,定义一个参数有效性的约束:

 

复制代码

 1 public class ValuesConstraint : IRouteConstraint

 2 {

 3     private readonly string[] validOptions;

 4     public ValuesConstraint(string options)

 5     {

 6         validOptions = options.Split('|');

 7     }

 8  

 9     public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)

10     {

11         object value;

12         if (values.TryGetValue(parameterName, out value) && value != null)

13         {

14             return validOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);

15         }

16         return false;

17     }

18 }

复制代码

然后将自定义的约束进行注册:

 

复制代码

 1 public class RouteConfig

 2 {

 3     public static void RegisterRoutes(RouteCollection routes)

 4     {

 5         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 6  

 7         var constraintsResolver = new DefaultInlineConstraintResolver();

 8  

 9         constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));

10  

11         routes.MapMvcAttributeRoutes(constraintsResolver);

12     }

13 }

复制代码

现在,你就可以在你的路由中使用该自定义的约束了

 

复制代码

1 public class TemperatureController : Controller

2 {

3     // eg: temp/celsius and /temp/fahrenheit but not /temp/kelvin

4     [Route("temp/{scale:values(celsius|fahrenheit)}")]

5     public ActionResult Show(string scale)

6     {

7         return Content("scale is " + scale);

8     }

9 }

复制代码

路由名

你可以为一个路由指定一个名称,以便生成相应的url。例如: 

 

1 [Route("menu", Name = "mainmenu")]

2 public ActionResult MainMenu() { ... }

你可以使用 Url.RouteUrl 来生成相应的 URL

 

1 <a href="@Url.RouteUrl("mainmenu")">Main menu</a>

区域(Area)

你可以使用特性[RouteArea]指定一个控制器属于某个区域,当这样做时,你可以安全的移除该区域的AreaRegistration 类:

 

复制代码

 1 [RouteArea("Admin")]

 2 [RoutePrefix("menu")]

 3 [Route("{action}")]

 4 public class MenuController : Controller

 5 {

 6     // eg: /admin/menu/login

 7     public ActionResult Login() { ... }

 8  

 9     // eg: /admin/menu/show-options

10     [Route("show-options")]

11     public ActionResult Options() { ... }

12  

13     // eg: /stats

14     [Route("~/stats")]

15     public ActionResult Stats() { ... }

16 }

复制代码

使用该控制器,下面的链接将产生下面的url:"/Admin/menu/show-options"

 

Url.Action("Options", "Menu", new { Area = "Admin" })

你也可以使用AreaPrefix参数建立一个自定义的区域前缀,例如:

 

[RouteArea("BackOffice", AreaPrefix = "back-office")]

如果你同时使用带有路由特性的区域和带有(AreaRegistration 类创建的)传统路由的区域这两种方式 的话,你应该在配置MVC路由特性之后,默认传统路由之前注册区域,原因很简单,路由注册顺序必须是从最精确的匹配规则开始再到普通的匹配规则,最后才是模糊的匹配规则,这样就避免了在进行路由匹配时,过早的匹配了模糊规则,而相对精确的匹配起不到任何作用。下面的例子展示了这一点:

 

复制代码

 1 public static void RegisterRoutes(RouteCollection routes)

 2 {

 3     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 4  

 5     routes.MapMvcAttributeRoutes();

 6  

 7     AreaRegistration.RegisterAllAreas();

 8  

 9     routes.MapRoute(

10         name: "Default",

11         url: "{controller}/{action}/{id}",

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

13     );

14 }

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网