【翻译】ASP.NET MVC 5属性路由

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

最近在学习MVC相关的东西,今天刚好到msdn上看到了这样的一片文章,感觉不错,于是决定将它翻译出来和博友们一起分享下。我第一次发表文章,有不对的地方非常欢迎指出。

                                                      —— 写在前面

废话不多说了,咱们开始吧

路由是ASP.NET MVC 怎样去用一个URI去匹配一个Action 。MVC5 支持一个新类型的路由,叫做属性路由。就像这个名字所说的,属性路由用属性去定义路由。在我们的web 应用程序中,属性路由给了我们URI更多的控制权。

之前我们用的路由方式,叫做基本的约定路由,现在仍然完全支持。你也可以在同一个项目中结合两种技术。

这篇文章将覆盖ASP.NET MVC 5属性路由的基本特点以及怎样去使用

一、为什么叫做属性路由

二、怎样去使用属性路由

三、可选的URI参数和默认路由

四、路由前缀

五、默认路由

六、路由约束以及自定义路由约束

七、给路由取个名字

八、区域(Areas)

一、为什么叫做属性路由

举个例子吧,在社会上比较好的的电子商务网站可能有如下的路由:

    • {productId:int}/{productTitle}
      映射到: ProductsController.Show(int id)
    • {username}
      映射到: ProfilesController.Show(string username)
    • {username}/catalogs/{catalogId:int}/{catalogTitle}
      映射到: CatalogsController.Show(string username, int catalogId)
      (不在太在意这些特殊的语法,我们将在之后讲解中会涉及到)

   在之前版本的ASP.NET MVC中,路由规则将在RouteConfig.cs文件中设置,它指出了真实的控制器和方法名,列如:

1 routes.MapRoute(
2         name: "ProductPage",
3         url: "{productId}/{productTitle}",
4         defaults: new { controller = "Products", action = "Show" },
5         constraints: new { productId = "\\d+" }
6     );

属性路由可以是我们更容易的去映射一个URI到一个Acion,上面的用属性路由我们就可以这样写:

1 [Route("{productId:int}/{productTitle}")]
2     public ActionResult Show(int productId) { ... }

二、怎样去使用属性路由

要去使用属性路由,必须先在到配置中去调用MapMvcAttributeRoutes

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         }

我们也可以结合属性路由去对路由做一个基本的约束

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

            routes.MapMvcAttributeRoutes();

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

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

你可以通过增加一个 "?" 标记到路由参数上去使用一个可选的URI参数。可以通过 parameter=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",前者是去返回所有的Book,而后者是返回指定的Book。

四、路由前缀

通常在一个控制器中,都以相同的前缀开始,例如:

 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         }

如果需要的话,你也可在Acion上用 “~" 去重写路由属性

1  [RoutePrefix("reviews")]
2     public class ReviewsController : Controller
3     {
4         // eg.: /spotlight-review
5         [Route("~/spotlight-review")]
6         public ActionResult ShowSpotlight() { ... }
7
8         ...
9     }

五、默认路由

我们也可以在一个Controller上去使用[Route],这个路由将被用在这个控制器所有的action上,除非一个指定的路由[Route]已经被用在一个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         }

六、路由约束

路由约束可以让我们去限制怎样去匹配路由参数,例如

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是整数时,才被匹配;否则第二个路由将被匹配

下表列出了可支持的约束下表列出了可支持的约束

Constraint Description Example
alpha Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) {x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches a DateTime value. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
length Matches a string with the specified length or within a specified range of lengths. {x:length(6)}
{x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:regex(^\d{3}-\d{3}-\d{4}$)}

要注意一些约束,例如 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     }

八、路由名字

我们也可以为路由指定一个名字,这样可以方便我们去生成它

1     [Route("menu", Name = "mainmenu")]
2     public ActionResult MainMenu() { ... }
1     <a href="@Url.RouteUrl("mainmenu")">Main menu</a>

哈哈,很爽吧

九、Areas

我们可以使用RouteArea属性,去让控制器属于一个Area

 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     }

下面的链接最终生成的就是"/Admin/menu/show-options"了

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

如果我们在同时使用用Areas和属性路由,Areas的路由基于我们在AreaRegistration中设置的,你需要去确保在配置中Area注册是在MVC 属性路由注册之后,对于这两种配置,我们都应该在 默认路由之前去注册。原因我想我不用说都应该很清楚吧,哪一个先去注册,那一个路由配置就最先去匹配URI,匹配不成功再交给下一个路由配置,例如

 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     }

终于翻译完了,由于这是本人是第一次翻译,英语水平也不太好,可能会有部分中式英语在里面以及一些其他不对的问题。如果有博友发现有问题我会立即更正的,谢谢!

原文链接在顶部已经贴出来了,有兴趣的也可以去看一下原文。

时间: 2024-10-05 20:51:34

【翻译】ASP.NET MVC 5属性路由的相关文章

[翻译:ASP.NET MVC 教程]创建路由约束

赶集要发:http://www.ganji18.com 你使用路由约束来使浏览器请求限制在匹配特定路由的中.你可以使用一个正则表达式来具体化一个路由约束. 例如,设想你已在Global.asax文件中定义了清单1中的路由. 清单1--Global.asax.cs routes.MapRoute( "Product", "Product/{productId}", new {controller="Product", action="De

为ASP.NET MVC应用添加自定义路由

这里,我们将学习如何给asp.net mvc应用添加自定义路由.用自定义路由来修改默认路由表. 对一些简单的asp.net mvc应用,默认的路由表就已经足够了.但是,当你需要创建特殊的路由时,就需要创建自定义路由了. 假设正在进行一个blog项目的开发,希望处理用户的请求地址如下: /Archive/12-25-2009 当用户输入这个URL时,你想返回日期12-25-2009的blog入口,为了实现这个路由,需要添加自定义路由. 在这个asp.net mvc应用中,这个方法中含有一个自定义路

ASP.NET MVC学习之路由篇(1)

原文:ASP.NET MVC学习之路由篇(1) 一.前言 作为一个从ASP.NET转入到ASP.NET MVC的开发人员而言,可能在开发ASP.NET网站的时候就已经开始在使用路由了. 只不过在ASP.NET MVC中路由是关键部分,而在ASP.NET中需要自行加进去.下面我们将学习ASP.NET MVC中的路由 系统. 二.准备工作 1.新建一个ASP.NET MVC4项目 2.模板选择空 3.在Controllers中添加一个Home控制器 4.打开App_Start中的RouteConfi

[ASP.NET MVC] URL网址路由包含&ldquo;/&rdquo;斜线

ASP.NET MVC 网址包含"/"斜线 笔者碰到一个状况是,URL带入的参数是可能有"/"斜线的(使用者输入)像是以下 1.运行正常 http://localhost:45405/Home/Product?name=HTC/M8/手机套 2.运行正常 http://localhost:45405/Home/Product?name='抗涨'白人牙膏_特大号 到目前为止都还没问题,但我们为了让URL好看以及优化SEO,我们会做URL Rewriting像是以下 1

ASP.NET MVC 的URL路由介绍

在这个教程中,向你介绍每个ASP.NET MVC一个重要的特点叫做URL路由.URL路由模块是负责映射从浏览器请求到特定的控制器动作. 在教程的第一部分,你将学习标准路由表如何映射到控制器的动作.在教程第二部分,你将学习如何修改默认路由表成为自定义路由. 使用默认路由表 当你创建一个新的ASP.NET MVC 应用程序,应用程序已经配置了默认的URL路由.URL路由在两个地方设置. 第一,URL路由配置在你的应用程序WEB配置文件中(Web.config文件).文件中有四个有关路由的配置 节:s

MVC 5 属性路由中添加自己的自定义约束

介绍约束 ASP.NET MVC和web api 同时支持简单和自定义约束,简单的约束看起来像: routes.MapRoute("blog", "{year}/{month}/{day}", new { controller = "blog", action = "index" }, new { year = @"\d{4}", month = @"\d{2}", day = @&qu

ASP.NET MVC教程五:ASP.NET MVC中的路由

一.概述 在ASP.NET MVC架构中,控制器在3大核心构件中处于中心地位,通过控制器支配模型和视图,然而从浏览器发出的请求到控制器还需要路由的协助,路由将特定的请求和控制器的动作对应起来. 在ASP.NET MVC程序中,路由主要有两方面的职责: 与入站的请求相匹配,将这些请求映射到控制器的动作中. 构造出站的URL,这些URL可以响应控制器的动作. 二.路由原理 1.注册路由 先看Global.asax中的代码: 网站启动的时候执行Application_Start方法,通过RouteCo

ASP.NET MVC学习之路由篇(3)

根据路由输出链接 既然是网站开发自然少不了链接,我们已经学会了强大的路由,但是还缺少一步就是能够将这些路由的路径输出到页面,下面我们就开始学习如何输出路由路径. 首先我们的路由注册部分如下所示: 1 namespace MvcStudy 2 { 3 public class RouteConfig 4 { 5 public static void RegisterRoutes(RouteCollection routes) 6 { 7 routes.Add(new Route("MyTest&q

ASP.NET MVC学习之路由篇(2)

7.解决与物理路径的冲突 当发送一个请求至ASP.NET MVC时,其实会检查网站中存不存在这个请求的物理路径文件,如果存在的话,就会直接将这个物理文件返回.但是有时候我们需要它执行控制器的某个方法,而不是直接将这个物理文件返回.那么我们就需要这节知识.下面我们先在网站根目录中新建一个 Test.html ,在其中随便写上一些内容,然后访问.再在RouteConfig.cs中写入如下代码: 1 public class RouteConfig 2 { 3 public static void R