特性路由
特性路由是对现有路由系统的扩展,提供了一种针对某个具体Controller类型或Action方法的路由注册方式。从而可以对路由规则进行细粒度的设计。
特性路由(Attribute Route)就是利用标注在Controller类型或Action方法上的特性来提供路由规则的路由注册方式。
1、 注册
默认情况下特性路由功能是关闭的,需要调用RouteCollection的扩展方法MapMvcAttributeRoutes来开启。
这个方法的调用要放在路由注册之前。
public static void RegisterRoutes(RouteCollection routes)
{ routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); RouteTable.Routes.MapMvcAttributeRoutes(); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );}public class MoviesController : Controller
{ // GET: Movies public ActionResult Index() { return View(); } [HttpGet] [Route("movies/{id}")] public ActionResult GetMoviesById(string id) { ViewBag.id = id; return View(); } [HttpGet] [Route("movies/starring/{starring}")] [Route("movies/starring/{starring}/{genre}")] [Route("movies/director/{director}/{genre}")] public ActionResult FindMovies(string starring, string director, string genre) { ViewBag.starring = starring; ViewBag.director = director; ViewBag.genre = genre; return View(); }}默认情况下使用特性类型RouteAttribute,它实现了接口IRouteInfoProvider。

当使用RouteAttribute时,需要提供一个路由模版来对Template这个只读属性进行初始化。而如果需要用这个路由特性注册的路由对象来生成URL,还需要为它提供一个Name,以便可以从路由表中把它提取出来。
2、 为特性路由的变量添加约束
路由变量基本都会直接绑定到目标Action方法相应的参数上,由于这些变量值在请求URL中以字符串的形式体现,所以被绑定参数必需支持源自字符串的类型转换。
为了确保参数绑定的正常进行,需要对路由变量在数据类型上进行约束。这些约束可以直接以内联的形式定义在路由模版里。
[HttpGet]
[Route("movies/{id:range(20,50)}")]public ActionResult GetMoviesById(int id)对于路由系统来说,约束通过RouteContraint对象来表示,所有RouteContraint类型均实现了IRouteContraint接口。
特性路由的这些以内联形式定义在路由模版中的约束,它们的约束类型也是实现了IRouteContraint接口。
| 约束 | 描述 | 用法 | 类型 |
| bool | 类型匹配 (布尔类型) | {x:bool} | BoolRouteContraint |
| datetime | 类型匹配 (DateTime类型) | {x:datetime} | DateTimeRouteContraint |
| decimal | 类型匹配 (Decimal类型) | {x:decimal} | DecimalRouteContraint |
| double | 类型匹配 (Double类型) | {x:double} | DoubleRouteContraint |
| float | 类型匹配 (Float类型) | {x:float} | FloatRouteContraint |
| guid | 类型匹配 (Guid类型) | {x:guid} | GuidRouteContraint |
| int | 类型匹配 (32位整数) | {x:int} | IntRouteContraint |
| long | 类型匹配 (64位整数) | {x:long} | LongRouteContraint |
| alpha | 字符组成(必须有拉丁字母组成) | {x:alpha} | AlphaRouteContraint |
| regex | 字符组成(必须与指定的正则匹配) | {x:regex(^\d{3}-\d{3}-\d{4}$)} | RegexRouteContraint |
| max | 值范围(小于或等于指定的最大值) | {x:max(20)} | MaxRouteContraint |
| min | 值范围(大于或等于指定的最小值) | {x:max(20)} | MinRouteContraint |
| range | 值范围(在指定的最大值和最小值之间) | {x:range(20,50)} | RangeRouteContraint |
| maxlength | 字符串长度(小于或等于指定的最大长度) | {x:maxlength(20)} | MaxLengthRouteContraint |
| minlength | 字符串长度(大于或等于指定的最小长度) | {x:minlength(20)} | MinlengthRouteContraint |
| length | 字符串长度(等于指定的长度或者在指定的范围内) | {x:length(6)} | LengthRouteContraint |
3、 为路由变量设置缺省值
1.将对应的参数定义为可缺省参数,路由模版里使用“?”
[HttpGet]
[Route("movies/language/{language?}")]public ActionResult GetMoviesByLanguage(string language = "en"){ return View();}2.将默认值定义在路由模版中
[HttpGet]
[Route("movies/language/{language=en}")]public ActionResult GetMoviesByLanguage(string language){ return View();}4、 设置模版前缀
使用RoutePrefixAttribute类型的特性,它只有一个只读属性Prefix,表示目标Controller所有Action方法共享的URL前缀。这个属性只能应用在Controller类型上,且只能有一个。

[RoutePrefix("movies")]
public class MoviesController : Controller{ [HttpGet] [Route("{id:range(20,50)}")] public ActionResult GetMoviesById(int id) { ViewBag.id = id; return View(); } [HttpGet] [Route("starring/{starring}")] [Route("starring/{starring}/{genre}")] [Route("director/{director}/{genre}")] public ActionResult FindMovies(string starring, string director, string genre) { ViewBag.starring = starring; ViewBag.director = director; ViewBag.genre = genre; return View(); } [HttpGet] [Route("~/actors/{criteria}")] //使用“~”为前缀,屏蔽掉Controller类型上的前缀“movies” public ActionResult FindActors(string criteria) { return View(); }}5、 设置Area名
使用RouteAreaAttribute类型的特性,它由两个属性AreaName和AreaPrefix,默认情况下使用AreaName做模版前缀,如果希望具有一个不同于Area名称的前缀,则要通过设置AreaPrefix属性来实现。
如果没有使用字符“~”前缀,特性路由的完整格式为{AreaPrefix}/{RoutePrefix}/{Template} 或者{AreaName}/{RoutePrefix}/{Template} 。

[RouteArea("MoviesArea")]//[RouteArea()]
[RoutePrefix("movies")]public class MoviesController : Controller{ [HttpGet] [Route("{id:range(20,50)}")] public ActionResult GetMoviesById(int id) { ViewBag.id = id; return View(); } [HttpGet] [Route("starring/{starring}")] [Route("starring/{starring}/{genre}")] [Route("director/{director}/{genre}")] public ActionResult FindMovies(string starring, string director, string genre) { ViewBag.starring = starring; ViewBag.director = director; ViewBag.genre = genre; return View(); } [HttpGet] [Route("~/admin/actors/{criteria}")] //使用“~”为前缀,屏蔽掉Controller类型上的前缀“movies” public ActionResult FindActors(string criteria) { return View(); }}
6、 直接应用到Controller上的RouteAttribute
[RouteArea("vedio")]
[RoutePrefix("movies")][Route("{action}/{id}", Name = "FindMovies")]public class MoviesController : Controller{ public ActionResult Index(string id) { throw new NotImplementedException(); }}
浙公网安备 33010602011771号