首页 > 代码库 > ASP.NET MVC 中的路由

ASP.NET MVC 中的路由

普通的路由

在以前版本的ASP.NET MVC里,这些规则会被定义在RouteConfig.cs文件,也有Routing Assistant扩展可以实现基于特性的路由,不过是收费滴,另外还有一个扩展:http://attributerouting.net/ ,也很不错;理论上ASP.NET MVC 中要实现任意的规则URL 应该是没有问题的。

比如配置的酒店详情页路由

              //HOTEL DETAIL            routes.MapRoute(name: "HotelDetail",                        url: "hotel/{hotelCd}",                        defaults: new { controller = "Hotel", action = "HotelDetail" },                        constraints: new { controller = "Hotel", hotelCd = @"[a-zA-Z0-9]*" }            );

自定义路由约束

如果是要精确到数据是否准确,可以自定义的路由规则,实现 IRouteConstraint 接口,重写Match方法即可。

public class CityConstraint : IRouteConstraint    {        /// <summary>        /// 匹配二级城市的URL        /// </summary>        /// <param name="httpContext"></param>        /// <param name="route"></param>        /// <param name="parameterName"></param>        /// <param name="values"></param>        /// <param name="routeDirection"></param>        /// <returns></returns>        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)        {            try            {                if (values["cityName"] == null || values["cityName"].ToString().ContainsAny(new string[] { "home", "list", "hotel", "member", "activity", "ajax","alipay", "gift"}))                {                    return false;                }                var city = CacheData.getCitys().Where(data =http://www.mamicode.com/> data.Pinyin.Equals(values["cityName"].ToString(), StringComparison.OrdinalIgnoreCase)).ToList();                if (city == null || city.Count == 0)                {                    return false;                }                return true;            }            catch (Exception ex)            {                return false;            }        }           routes.MapRoute(               name: "HotelCity",               url: "{cityName}/p{pageNo}",               defaults: new { controller = "HotelSEO", action = "Hotel", pageNo = "1" },               constraints: new { cityName = new CityConstraint(), pageNo = @"\d+" }                //constraints: new { cityName = @"(|shanghai|beijing|hefei|chuzhou)"}             );

考虑到hotel/xxx可以匹配到酒店编号不符合规则的酒店,也可能是用户手误打错了,可以捕获所有以hotel开头不符合正则的的URL到酒店的目录页

routes.MapRoute(name: "HotelMenu",                           url: "hotel/{*values}",                           defaults: new { controller = "Menu", action = "Index" }            );

特性路由

要启用特性路由,只要项目中注册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参数和默认值

    // eg: /hotel    // eg: /hotel/123456    [Route("hotel/{hotelCd?}")]    public ActionResult View(string hotelCd)    {        if (!String.IsNullOrEmpty(hotelCd))        {            return View("HotelDetail", GetHotelDetail(hotelCd));        }        return View("HotelMenu", GetHotelCitys());    }

路由前缀

比如现在的会员页面,都是以user 开头的如

// eg: /user    [Route("user")]    public ActionResult Index() { ... }    // eg: /user/5    [Route("user/{userId}")]    public ActionResult Show(int userId) { ... }    // eg: /user/5/edit    [Route("user/{userId}/edit")]    public ActionResult Edit(int userId) { ... }

这个时候也在控制器加一个全局[RoutePrefix]特性

[RoutePrefix("user")]public class userController : Controller{    // eg.: /user    [Route]    public ActionResult Index() { ... }    // eg.: /user/5    [Route("{userId}")]    public ActionResult Show(int userId) { ... }    // eg.: /user/5/edit    [Route("{userId}/edit")]    public ActionResult Edit(int userId) { ... }}

重写路由规则

如果有的时候需要重写路由规则,就加个波浪线 ~

[RoutePrefix("review")]public class ReviewController : Controller{    // eg.: /code-review    [Route("~/code-review")]    public ActionResult CodeView() { ... }}

也可以在controller中定义Route特性,将action作为一个参数。这个路由会被应用到controller上的所有action,除非某个action已经定义了一个[Route]特性,重写controller的默认行为。

[RoutePrefix("user")][Route("{action=Index}")]public class ReviewsController : Controller{    // eg.: /user    public ActionResult Index() { ... }     // eg.: /user/set    public ActionResult Set() { ... }     // eg.: /user/new    public ActionResult New() { ... }     // eg.: /user/edit/5    [Route("edit/{userId:int}")]    public ActionResult Edit(int promoId) { ... }}

路由约束

路由约束让你可以限制参数在路由模板里如何匹配。通常的语法是{parameter:constraint},如:

// eg: /users/5[Route("users/{id:int}"]public ActionResult GetUserById(int id) { ... }// eg: users/ken[Route("users/{name}"]public ActionResult GetUserByName(string name) { ... }

支持的约束类型:

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}$)}

可以用分号分隔,定义多个约束,如:

// 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) { ... }

比如MS的这篇文章,大致可以配置成如下的路由规则:
http://blogs.msdn.com/b/webdev/archive/2014/03/04/asp-net-mvc-5-lifecycle-document-published.aspx
[Route("/b/webdev/archive/{year:regex(\\d{4})}")]
[Route("/b/webdev/archive/{year:regex(\\d{4})}/{month:regex(\\d{1,2})}")]
[Route("/b/webdev/archive/{year:regex(\\d{4})}/{month:regex(\\d{1,2})}/{day:regex(\\d{1,2})}/{slug}")]
public ActionResult GetArchivePost(string year, string month,string day,string slug){ };

特性路由中自定义路由约束

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=http://www.mamicode.com/"@Url.RouteUrl("mainmenu")">Main menu</a>

特性路由VS普通的路由

其实这个问题与Spring是基于xml配置好,还是注解的方式好,具体还得看使用场景,每一种方式都有自己的优势与劣势,比如基于普通的路由可以自定义直接 的一些逻辑,基于特性的路由可以快速现实一个路由的实现。

        // eg: /books/lang        // eg: /books/lang/en        // eg: /books/lang/he        [Route("books/lang/{lang=en}")]        public ActionResult Lang(string lang)        {            return View();        }        [Route("~/attribute-routing-in-asp-net-mvc-5")]        public ActionResult Hotel()        {            return Content("I‘am mvc attribute route! ");        }

Refer:
What’s New in ASP.NET MVC 5.2
http://www.asp.net/mvc/overview/releases/whats-new-in-aspnet-mvc-52
http://attributerouting.net/

ASP.NET MVC 中的路由