• 【翻译】ASP.NET MVC 5属性路由(转)


    转载链接:http://www.cnblogs.com/thestartdream/p/4246533.html

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

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

    ConstraintDescriptionExample
    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     }
    复制代码

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

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

  • 相关阅读:
    《python基础教程 》第二章 读书笔记
    hdu 4462 Scaring the Birds 解题报告
    hud 4454 Stealing a Cake 解题报告
    uva 532 Dungeon Master
    《python基础教程 》第一章 读书笔记
    开源项目资源站点
    syslog() 函数简单解析
    ftruncate()函数
    Mysql数据库函数
    int mysql_options() mysql_real_connect() mysql_real_query()/mysql_real_escape_string
  • 原文地址:https://www.cnblogs.com/yxlblogs/p/4866608.html
Copyright © 2020-2023  润新知