• ASP.NET MVC 中的路由


    普通的路由

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

    Attribute routing

    ASP.NET MVC now supports attribute routing, thanks to a contribution by Tim McCall, the author of http://attributerouting.net. With attribute routing you can specify your routes by annotating your actions and controllers.

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

                  //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 => 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="@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
    http://www.asp.net/mvc/mvc5
    What’s New in ASP.NET MVC 5.2
    http://www.asp.net/mvc/overview/releases/whats-new-in-aspnet-mvc-52
    attribute-routing-in-asp-net-mvc-5
    http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx

  • 相关阅读:
    集群间Session共享问题解决方案
    session原理及实现共享
    【单点登录】【两种单点登录类型:SSO/CAS、相同一级域名的SSO】
    HashMap与ConcurrentHashMap的区别
    Java的文件读写操作
    Spring之ClassPathResource加载资源文件
    3万的支付订单请求并发解决方案
    java中的队列
    互联网应用在高并发
    四种Java线程池用法解析
  • 原文地址:https://www.cnblogs.com/Irving/p/3996599.html
Copyright © 2020-2023  润新知