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


目錄

概述

路由特性

使用路由

可選參數和參數的默認值

路由前綴

默認路由

路由約束

自定義路由約束

路由名

區域(Area)

總結

系列文章

[Asp.net MVC]Asp.net MVC5系列——第一個項目

[Asp.net MVC]Asp.net MVC5系列——添加視圖

[Asp.net MVC]Asp.net MVC5系列——添加模型

[Asp.net MVC]Asp.net MVC5系列——從控制器訪問模型中的數據

[Asp.net MVC]Asp.net MVC5系列——添加數據

[Asp.net MVC]Asp.net MVC5系列——在模型中添加驗證規則 

[Asp.net MVC]Asp.net MVC5系列——實現編輯、刪除與明細信息視圖

[Asp.net MVC]Asp.net MVC5系列——Razor語法

概述

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 }

 

 

總結

本文主要學習了asp.net mvc5路由的新特性,在查看mvc5的資料的時候,看到的一篇文章,覺得不錯,就認真的看了一遍,試着用自己的語言翻譯了原文,也許有翻譯不到位的地方,望諒解,如果你英語不錯,也可以參考原文。

原文地址:http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM