ASP.NET MVC 5中的属性路由

路由是ASP.NET MVC如何将URL与动作匹配。MVC 5支持一种新的路由,称为属性路由。顾名思义,属性路由使用属性来定义路由。属性路由使您对Web应用程序中的URL有更多的控制权。

早期的路由方式,称为基于约定的路由,仍然完全支持。事实上,您可以在同一个项目中组合这两种技术。

本文将介绍ASP.NET MVC 5中属性路由的基本特征和选项。

  • 为什么属性路由?
  • 启用属性路由
  • 可选URL参数和默认值
  • 路由前缀
  • 默认路由
  • 路由约束
     自定义路由约束
  • 路由名称
  • 区域

一、为什么属性路由

例如,一个社会化增强的电子商务网站可以有以下路线:

  • {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文件中设置,并指向实际的控制器动作,例如:

routes.MapRoute(

name: “ProductPage”,

url: “{productId}/{productTitle}”,

defaults: new { controller = “Products”, action = “Show” },

constraints: new { productId = “\\d+” }

);

当路由定义与操作共处时,在同一源文件中,而不是在外部配置类上声明,这样就可以更容易地推断URL与操作之间的映射。前面的路由定义将使用以下简单的属性来设置:

[Route(“{productId:int}/{productTitle}”)]

public ActionResult Show(int productId) { … }


二、启用属性路由

若要启用属性路由,请在配置过程中调用MapMvcAttributeRoutes

public class RouteConfig

{

public static void RegisterRoutes(RouteCollection routes)

{

routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);

routes.MapMvcAttributeRoutes();

}

}

还可以将属性路由与基于约定的路由相结合

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 }

);

}

 

三、可选URL参数和默认值

可以通过向路由参数添加问号来选择URL参数。还可以使用窗体参数=值指定默认值

public class BooksController : Controller

{

// eg: /books

// eg: /books/1430210079

[Route(“books/{isbn?}”)]

public ActionResult View(string isbn)

{

if (!String.IsNullOrEmpty(isbn))

{

return View(“OneBook”, GetBook(isbn));

}

return View(“AllBooks”, GetBooks());

}

// eg: /books/lang

// eg: /books/lang/en

// eg: /books/lang/he

[Route(“books/lang/{lang=en}”)]

public ActionResult ViewByLanguage(string lang)

{

return View(“OneBook”, GetBooksByLanguage(lang));

}

}

在这个示例中,/books和/./1430210079都将路由到“View”操作,前者将列出所有图书,后者将列出特定图书。/books/lang and /books/lang/en 都会得到同样的对待

四、路由前缀

通常,控制器中的路由都以相同的前缀开头。例如:

public class ReviewsController : Controller

{

// eg: /reviews

[Route(“reviews”)]

public ActionResult Index() { … }

// eg: /reviews/5

[Route(“reviews/{reviewId}”)]

public ActionResult Show(int reviewId) { … }

// eg: /reviews/5/edit

[Route(“reviews/{reviewId}/edit”)]

public ActionResult Edit(int reviewId) { … }

}

可以使用[RouTePiFix]属性设置整个控制器的公共前缀:

[RoutePrefix(“reviews”)]

public class ReviewsController : Controller

{

// eg.: /reviews

[Route]

public ActionResult Index() { … }

// eg.: /reviews/5

[Route(“{reviewId}”)]

public ActionResult Show(int reviewId) { … }

// eg.: /reviews/5/edit

[Route(“{reviewId}/edit”)]

public ActionResult Edit(int reviewId) { … }

}

如果需要的话,在方法属性上使用一个TrdE(~)来重写路由前缀:

[RoutePrefix(“reviews”)]

public class ReviewsController : Controller

{

// eg.: /spotlight-review

[Route(“~/spotlight-review”)]

public ActionResult ShowSpotlight() { … }

…

}

五、默认路由

还可以在控制器级别上应用[Route]属性,将操作捕获为参数。然后,该路由将应用于控制器中的所有操作,除非在特定操作上定义了特定的[Route],从而覆盖控制器上的默认设置

[RoutePrefix(“promotions”)]

[Route(“{action=index}”)]

public class ReviewsController : Controller

{

// eg.: /promotions

public ActionResult Index() { … }

// eg.: /promotions/archive

public ActionResult Archive() { … }

// eg.: /promotions/new

public ActionResult New() { … }

// eg.: /promotions/edit/5

[Route(“edit/{promoId:int}”)]

public ActionResult Edit(int promoId) { … }

}

六、路由约束

路由约束使您可以限制路由模板中的参数是如何匹配的。一般语法是{参数:约束}。例如:

// eg: /users/5

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

public ActionResult GetUserById(int id) { … }

// eg: users/ken

[Route(“users/{name}”]

public ActionResult GetUserByName(string name) { … }

这里,如果URL的“ID”段是整数,则只选择第一条路径。否则,将选择第二条路线。

下表列出了所支持的约束。

约束

描述

示例

alpha匹配大写或小写拉丁字母字符(A z,A z){x:alpha}
bool匹配布尔值{x:bool}
datetime匹配DateTime值{x:datetime}
decimal匹配decimal值{x:decimal}
double匹配一个64位浮点值{x:double}
float匹配32位浮点值{x:float}
guid匹配GUID值{x:guid}
int匹配32位整数值{x:int}
length在指定长度范围内匹配具有指定长度的字符串{x:length(6)} 
{x:length(1,20)}
long匹配一个64位整数值{x:long}
max匹配具有最大值的整数{x:max(10)}
maxlength匹配具有最大长度的字符串{x:maxlength(10)}
min匹配具有最小值的整数{x:min(10)}
minlength匹配具有最小长度的字符串{x:minlength(10)}
range匹配一个值范围内的整数{x:range(10,50)}
regex匹配正则表达式{x:regex(^\d{3}-\d{3}-\d{4}$)}

请注意,一些约束,如“min”,在括号中使用参数。

可以将多个约束应用于一个参数,例如用冒号分隔开,例如:

// eg: /users/5
// but not /users/10000000000 because it is larger than int.MaxValue,
// and not /users/0 because of the min(1) constraint.

[Route(“users/{id:int:min(1)}”)]

public ActionResult GetUserById(int id) { … }


指定一个参数是可选的(通过?“修改器”应在内联约束之后完成:

// eg: /greetings/bye
// and /greetings because of the Optional modifier,
// but not /greetings/see-you-tomorrow because of the maxlength(3) constraint.
[Route(“greetings/{message:maxlength(3)?}”)]

public ActionResult Greet(string message) { … }

自定义路由约束

您可以通过实现IRouteConstraint接口来创建自定义路由约束。例如,以下约束将一个参数限制为有效值的集合:

public class ValuesConstraint : IRouteConstraint

{

private readonly string[] validOptions;

public ValuesConstraint(string options)

{

validOptions = options.Split(‘|’);

}

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

{

object value;

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

{

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

}

return false;

}

}

下面的代码演示如何注册约束:

public class RouteConfig

{

public static void RegisterRoutes(RouteCollection routes)

{

routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);

var constraintsResolver = new DefaultInlineConstraintResolver();

constraintsResolver.ConstraintMap.Add(“values”, typeof(ValuesConstraint));

routes.MapMvcAttributeRoutes(constraintsResolver);

}

}

现在你可以在你的路线中应用约束:

public class TemperatureController : Controller

{

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

[Route(“temp/{scale:values(celsius|fahrenheit)}”)]

public ActionResult Show(string scale)

{

return Content(“scale is “ + scale);

}

}

七、路由名称

您可以为路由指定一个名称,以便方便地为其生成URL。例如,对于以下路线:

[Route(“menu”, Name = “mainmenu”)]

public ActionResult MainMenu() { … }

您可以使用Url.RouteUrl生成链接:

<a href=”@Url.RouteUrl(“mainmenu”)“>Main menu</a>

八、区域

可以使用[RoutArea]属性定义控制器属于一个区域。这样做时,您可以安全地删除该区域的AreaRegistration类。

[RouteArea(“Admin”)]

[RoutePrefix(“menu”)]

[Route(“{action}”)]

public class MenuController : Controller

{

// eg: /admin/menu/login

public ActionResult Login() { … }

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

[Route(“show-options”)]

public ActionResult Options() { … }

// eg: /stats

[Route(“~/stats”)]

public ActionResult Stats() { … }

}

使用此控制器,字符串将产生以下链接生成调用“/Admin/menu/show-options

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

您可以通过使用名为参数的 AreaPrefix设置用于从区域名称推迟的区域的自定义前缀,例如:

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

如果同时使用带有路由属性的Area和基于约定的路由的区域(由AreaRegistration类设置),则需要确保在配置MVC属性路由之后进行区域注册,但是在设置默认的基于约定的路由之前。原因在于,路由注册应该从最特定的(属性)排序到更一般的(区域注册)到雾一般的(默认路由),以避免通用路由在流水线中太早地匹配传入的请求,从而“隐藏”更具体的路由。

示例:

public static void RegisterRoutes(RouteCollection routes)

{

routes.IgnoreRoute(“{resource}.axd/{*pathInfo}”);

routes.MapMvcAttributeRoutes();

AreaRegistration.RegisterAllAreas();

routes.MapRoute(

name: “Default”,

url: “{controller}/{action}/{id}”,

defaults: new { controller = “Home”, action = “Index”, id = UrlParameter.Optional }

);

}

原文地址:https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/#why-attribute-routing

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值