Asp.Net 自定义Route生成小写Url

为了给用户更好的体验,我们一般会保持网站的url一致,一般url均为小写,更加美观。

这里以MVC为例:

1. 在MVC 5.0 中,有一个属性,非常简单好用,我们直接在 RouteConfig 的静态方法 RegisterRoutes 中设置 routes.LowercaseUrls = true;即可。

    该属性用于 “ 获取或设置指示标准化虚拟路径时是否将 URL 转换为小写的值”。

2. 安装 LowsercaseRoutesMVC 组件,将RegisterRoutes方法中 routes.MapRoute 替换为 routes.MapRouteLowercase 即可。

3. 自己封装 Route来进行Url的匹配和解析。

  MVC中,路由数据是封装在 RouteData 中的,RouteData 结构如下代码所示

 1   public class RouteData
 2     {
 4         //确定路由是否匹配请求时,传递到路由处理程序但未使用的自定义值的集合。
 5         public RouteValueDictionary DataTokens { get; }
 6      
 7         //获取或设置表示路由的对象。
 8         public RouteBase Route { get; set; }
 9       
10         //获取或设置处理所请求路由的对象。(MVC框架中自定义的HttpHandler(IRouteHandler提供 GetHttpHandler方法)便从此处获得)
11         public IRouteHandler RouteHandler { get; set; }
13       
14         //获取路由的 URL 参数值和默认值的集合。
15         public RouteValueDictionary Values { get; }
17       
18         //  使用指定标识符检索值。
19         public string GetRequiredString(string valueName);
20     }

RouteData中,类型为RouteBase 的Route属性,表示生成路由数据对应的路由对象。RouteBase是一个抽象类,结构如下:

 

//返回有关请求路由信息
public abstract RouteData GetRouteData(HttpContextBase httpContext);

//重写时,检查路由,匹配则生成一个 URL,然后检索有关该路由的信息
public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);

 GetRouteData 用来解析Url,GetVirutalPath用来生成url. 常用的如:Url.Action,ActionLink、RouteLink、RedirectToAction 和 RedirectToRouter 内部都会调用 GetVirtualPath 方法来生成 Url。因为我们入手点便在重写的 GetVirutalPath 方法上。

 MVC 中 RouteBase 的具体实现类是 Route,我们经常在 Global.asax 中经常使用:

public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );
    }
    //...
}

MapRoute 返回 Route,我们可以写一个继承自 Route 的类,然后重写它的 GetVirtualPath 方法:直接贴代码

public class LowerCaseUrlRoute : Route
{
  

    /// <summary>
    /// 需要小写的键值
    /// </summary>

      private static readonly string[] requiredKeys = new [] {"area","culture", "controller", "action" };

   public LowerCaseUrlRoute(string url, IRouteHandler routeHandler)
        : base(url, routeHandler) { }
    
    public LowerCaseUrlRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
        : base(url, defaults, routeHandler){ }

    public LowerCaseUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
        : base(url, defaults, constraints, routeHandler) { }
  

    /// <summary>
    /// Initializes a new instance of the <see cref="LowerCaseUrlRoute"/> class.
    /// </summary>
    /// <param name="url">路由的 URL 模式。</param>
    /// <param name="defaults">要在 URL 不包含所有参数时使用的值。</param>
    /// <param name="constraints">一个用于指定 URL 参数的有效值的正则表达式。</param>
    /// <param name="dataTokens">传递到路由处理程序但未用于确定该路由是否匹配特定 URL 模式的自定义值。 这些值会传递到路由处理程序,以便用于处理请求。</param>
    /// <param name="routeHandler">处理路由请求的对象。</param>

public LowerCaseUrlRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
        : base(url, defaults, constraints, dataTokens, routeHandler) { }    
   
   //重写GetVirtualPath以生成小写Url
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) { LowerRouteValues(requestContext.RouteData.Values); LowerRouteValues(values); LowerRouteValues(Defaults); return base.GetVirtualPath(requestContext, values); }
  //转换要小写的键值
private void LowerRouteValues(RouteValueDictionary values) { foreach (var key in requiredKeys) { if (values.ContainsKey(key) == false) continue; var value = values[key]; if (value == null) continue; var valueString = Convert.ToString(value, CultureInfo.InvariantCulture); if (valueString == null) continue; values[key] = valueString.ToLower(); } var otherKyes = values.Keys .Except(requiredKeys, StringComparer.InvariantCultureIgnoreCase) .ToArray(); foreach (var key in otherKyes) { var value = values[key]; values.Remove(key); values.Add(key.ToLower(), value); } } }

自定义  LowerCaseUrlRoute 后,我们从网上直接Down一个 LowerCaseUrlRouter的扩展方法:代码如下

 public static class LowerCaseUrlRouteExtensions
    {
        /// <summary>
        /// LowerCaseUrlRouter的扩展方法
        /// </summary>
        /// <param name="routes"></param>
        /// <param name="name"></param>
        /// <param name="url"></param>
        /// <param name="defaults"></param>
        /// <returns></returns>
        public static LowerCaseUrlRoute MapUrl(this RouteCollection routes, string name, string url, object defaults)
        {
            var route = new LowerCaseUrlRoute(url,
                new RouteValueDictionary(defaults),
                new RouteValueDictionary(), //constraints
                new RouteValueDictionary(), //dataTokens
                new MvcRouteHandler());

            //获取当前项目控制器的Namespace,使其默认应用在这个Namespace下
            var type = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;
            if (type != null)
            {
                var namespaces = new[] { type.Namespace + ".Controllers" };
                route.DataTokens["Namespaces"] = namespaces;
            }

            routes.Add(name, route);
            return route;
        }

        public static LowerCaseUrlRoute MapUrl(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
        {
            var route = new LowerCaseUrlRoute(url,
                new RouteValueDictionary(defaults),
                new RouteValueDictionary(), //constraints
                new RouteValueDictionary(), //dataTokens
                new MvcRouteHandler());

            if ((namespaces != null) && (namespaces.Length > 0))
            {
                route.DataTokens["Namespaces"] = namespaces;
            }
            routes.Add(name, route);
            return route;
        }

        public static LowerCaseUrlRoute MapUrl(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
        {
            var route = new LowerCaseUrlRoute(url,
                new RouteValueDictionary(defaults),
                new RouteValueDictionary(constraints),
                new RouteValueDictionary(),
                new MvcRouteHandler());

            if ((namespaces != null) && (namespaces.Length > 0))
            {
                route.DataTokens["Namespaces"] = namespaces;
            }
            routes.Add(name, route);
            return route;
        }
    }
routes.MapUrl(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

修改RouteConfig中如上图所示,大功搞成!

    

  

    

posted @ 2015-05-14 01:19  ToBeStrong  阅读(309)  评论(0编辑  收藏  举报