How do I generically implement URL-rewriting in a MapRoute method?

前端 未结 2 1413
暗喜
暗喜 2021-01-22 06:40


I am attempting to rewrite URL\'s from C#\'s Pascal-case to SEO-friendly format.
For example, I want something like /User/Home/MyJumbledPageName to lo

相关标签:
2条回答
  • 2021-01-22 07:23


    For reference, I have found how to make @LostInComputer 's code work for areas as well. The class used for an area must implement IRouteWithArea for context.Routes.Add to work in an area's RegisterArea method.

    Here's a generic class that can be used for areas (it extends the above SEOFriendlyRoute class):

    public class AreaSEOFriendlyRoute : SEOFriendlyRoute, IRouteWithArea
    {
        private readonly string _areaName;
    
        // constructor:
        public AreaSEOFriendlyRoute(string areaName, string url, RouteValueDictionary defaults, IEnumerable<string> valuesToSeo,
            RouteValueDictionary constraints = null, RouteValueDictionary dataTokens = null, IRouteHandler routeHandler = null)
            : base(url, defaults, valuesToSeo, constraints, dataTokens, routeHandler)
        {
            this._areaName = areaName;
        }
    
        // implemented from IRouteWithArea:
        public string Area
        {
            get
            {
                return this._areaName;
            }
        }
    }
    


    ...and its' usage:

    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.Routes.Add("Example", new AreaSEOFriendlyRoute(
            areaName: this.AreaName,
            url: "my-area/{action}/{id}",
            valuesToSeo: new string[] { "action", "controller" },
            defaults: new RouteValueDictionary(new { controller = "MyController", action = "MyDefaultPage", id = UrlParameter.Optional }))
        );
    }
    


    Note that I am passing an extra argument when calling context.Routes.Add, which is defined as areaName. The formal parameter of the same name in the constructor is used to return this value from the Area method, in which is implemented from IRouteWithArea.


    So a link such as:

    @Html.ActionLink("my link text", "MyJumbledPageName", "MyController",
    new { area = "MyArea" }, null)
    


    ...would result in the url my-area/my-jumbled-page-name. Also note that the preceding "my-area" in the url is obtained by hard-coding this in the route's url argument.

    0 讨论(0)
  • 2021-01-22 07:29

    You have to define your own RouteBase class or subclass Route

    public class SeoFriendlyRoute : Route
    {
        private readonly string[] _valuesToSeo;
    
        public SeoFriendlyRoute(string url, RouteValueDictionary defaults, IEnumerable<string> valuesToSeo, RouteValueDictionary constraints = null, RouteValueDictionary dataTokens = null, IRouteHandler routeHandler = null)
            : base(url, defaults, constraints ?? new RouteValueDictionary(), dataTokens ?? new RouteValueDictionary(), routeHandler ?? new MvcRouteHandler())
        {
            if (valuesToSeo == null) { throw new ArgumentNullException("valuesToSeo"); }
            _valuesToSeo = valuesToSeo.ToArray();
        }
        public override RouteData GetRouteData(HttpContextBase httpContext)
        {
            var routeData = base.GetRouteData(httpContext);
            if (routeData != null)
            {
                foreach (var key in _valuesToSeo)
                {
                    if (routeData.Values.ContainsKey(key))
                    {
                        routeData.Values[key] = GetActualValue((string)routeData.Values[key]);
                    }
                }
            }
            return routeData;
        }
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            var seoFriendyValues = new RouteValueDictionary(values);
            foreach (var key in _valuesToSeo)
            {
                if (seoFriendyValues.ContainsKey(key))
                {
                    seoFriendyValues[key] = GetSeoFriendlyValue((string)seoFriendyValues[key]);
                }
            }
            return base.GetVirtualPath(requestContext, seoFriendyValues);
        }
    
        private string GetSeoFriendlyValue(string actualValue)
        {
            //your method
            StringBuilder str = new StringBuilder();
            for (int i = 0, len = actualValue.Length; i < len; i++)
            {
                if (i == 0)
                {
                    str.Append(Char.ToLower(actualValue[i]));
                }
                else if (Char.IsUpper(actualValue[i]))
                {
                    str.Append("-" + Char.ToLower(actualValue[i]));
                }
                else
                {
                    str.Append(actualValue[i]);
                }
            }
            return str.ToString();
        }
    
        private static string GetActualValue(string seoFriendlyValue)
        {
            //action name is not case sensitive
            //one limitation is the dash can be anywhere but the action will still be resolved
            // /my-jumbled-page-name is same as /myjumbled-pagename
            return seoFriendlyValue.Replace("-", string.Empty); 
        }
    }
    

    Usage

    routes.Add("Default", new SeoFriendlyRoute(
        url: "{controller}/{action}/{id}",
        valuesToSeo: new string[] { "action", "controller" },
        defaults: new RouteValueDictionary(new { controller = "Home", action = "Index", id = UrlParameter.Optional }))
    );
    
    0 讨论(0)
提交回复
热议问题