сделать URL строчными.Любой простой или встроенный способ? - PullRequest
47 голосов
/ 29 мая 2011

Есть ли какой-нибудь простой / встроенный способ сделать URL строчными для MVC3.

У меня есть код, который может это сделать, но я ищу что-то простое для реализации.

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

public class LowercaseRoute : Route
    {
        public LowercaseRoute(string url, IRouteHandler routeHandler)
            : base(url, routeHandler)
        {
        }

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

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

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

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            VirtualPathData path = base.GetVirtualPath(requestContext, values);

            if (path != null)
            {
                path.VirtualPath = path.VirtualPath.ToLowerInvariant();
            }

            return path;
        }
    }




public static class RouteCollectionExtensions
    {
        public static Route MapRouteLowercase(this RouteCollection routes, string name, string url)
        {
            return routes.MapRouteLowercase(name, url, null /* defaults */, (object)null /* constraints */);
        }

        public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults)
        {
            return routes.MapRouteLowercase(name, url, defaults, (object)null /* constraints */);
        }

        public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults, object constraints)
        {
            return routes.MapRouteLowercase(name, url, defaults, constraints, null /* namespaces */);
        }

        public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, string[] namespaces)
        {
            return routes.MapRouteLowercase(name, url, null /* defaults */, null /* constraints */, namespaces);
        }

        public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
        {
            return routes.MapRouteLowercase(name, url, defaults, null /* constraints */, namespaces);
        }

        public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
        {
            if (routes == null)
            {
                throw new ArgumentNullException("routes");
            }
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            Route route = new LowercaseRoute(url, new MvcRouteHandler())
            {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints),
                DataTokens = new RouteValueDictionary()
            };

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

            routes.Add(name, route);

            return route;
        }

        public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url)
        {
            return context.MapRouteLowercase(name, url, (object)null /* defaults */);
        }

        public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, object defaults)
        {
            return context.MapRouteLowercase(name, url, defaults, (object)null /* constraints */);
        }

        public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, object defaults, object constraints)
        {
            return context.MapRouteLowercase(name, url, defaults, constraints, null /* namespaces */);
        }

        public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, string[] namespaces)
        {
            return context.MapRouteLowercase(name, url, (object)null /* defaults */, namespaces);
        }

        public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, object defaults, string[] namespaces)
        {
            return context.MapRouteLowercase(name, url, defaults, null /* constraints */, namespaces);
        }

        public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, object defaults, object constraints, string[] namespaces)
        {
            if (namespaces == null && context.Namespaces != null)
            {
                namespaces = context.Namespaces.ToArray();
            }

            Route route = context.Routes.MapRouteLowercase(name, url, defaults, constraints, namespaces);
            route.DataTokens["area"] = context.AreaName;

            // disabling the namespace lookup fallback mechanism keeps this areas from accidentally picking up
            // controllers belonging to other areas
            bool useNamespaceFallback = (namespaces == null || namespaces.Length == 0);
            route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback;

            return route;
        }
    }

Ответы [ 6 ]

99 голосов
/ 21 августа 2012

Я только что заметил, что в .NET Framework 4.5 есть новое свойство.Работает отлично! RouteCollection.LowercaseUrls

Установите для LowercaseUrls значение true

public static void RegisterRoutes(RouteCollection routes)
{
    routes.LowercaseUrls = true;
    ...
}

Создать ссылку

@Html.ActionLink("Log in", "Login", "Account")

, которая создаст удивительный URL-адрес в нижнем регистре :)

<a href="/account/login">Log in</a>
17 голосов
/ 29 сентября 2011

Для этого есть пакет NuGet: LowerCaseRoutesMVC ( Сайт проекта )

12 голосов
/ 11 июля 2011

Если ваши причины для принудительного применения строчных букв - исключительно SEO, то лучшее решение, которое я нашел, это использовать модуль перезаписи URL IIS 7

Мало того, что у вас есть возможностьпринудительно переводите все URL в нижний регистр, но у вас также есть доступ к правилам, которые позволяют удалять / добавлять завершающие слэши, применять канонические домены и т. д.

Блог Руслана имеет хороший набор для начала.Например, я использую следующее на всех своих сайтах:

<!-- http://ruslany.net/2009/04/10-url-rewriting-tips-and-tricks/ -->
<rule name="Convert to lower case" stopProcessing="true">
    <match url=".*[A-Z].*" ignoreCase="false" />
    <conditions>
        <add input="{REQUEST_METHOD}" matchType="Pattern" pattern="GET" ignoreCase="false" />
    </conditions>
    <action type="Redirect" url="{ToLower:{R:0}}" redirectType="Permanent" />
</rule>

Вы просто добавляете вышеупомянутые строки в раздел вашего web.config.

1 голос
/ 11 июля 2011

Не уверен, что не так с вашим кодом (мой немного другой, но по сути та же концепция).Его очень легко реализовать, и его можно многократно использовать.

LowerCaseRouteHelper.cs

using System.Web.Routing;
using System.Web.Mvc;

namespace Utilities.Helpers
{
    public class LowercaseRouteHelper : System.Web.Routing.Route
    {
        public LowercaseRouteHelper(string url, IRouteHandler routeHandler) : base(url, routeHandler)
        {
        }
        public LowercaseRouteHelper(string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler)
        {
        }
        public LowercaseRouteHelper(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) : base(url, defaults, constraints, routeHandler)
        {
        }
        public LowercaseRouteHelper(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints, dataTokens, routeHandler)
        {
        }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            VirtualPathData path = base.GetVirtualPath(requestContext, values);

            if (path != null) {
                path.VirtualPath = path.VirtualPath.ToLowerInvariant();
            }

            return path;
        }
    }

    public static class RouteCollectionExtensions
    {
        [System.Runtime.CompilerServices.Extension()]
        public static void MapRouteLowercase(RouteCollection routes, string name, string url, object defaults)
        {
            routes.MapRouteLowercase(name, url, defaults, null);
        }

        [System.Runtime.CompilerServices.Extension()]
        public static void MapRouteLowercase(RouteCollection routes, string name, string url, object defaults, object constraints)
        {
            if (routes == null) {
                throw new ArgumentNullException("routes");
            }

            if (url == null) {
                throw new ArgumentNullException("url");
            }

            object route = new LowercaseRouteHelper(url, new MvcRouteHandler()) {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints)
            };

            if (String.IsNullOrEmpty(name)) {
                routes.Add(route);
            } else {
                routes.Add(name, route);
            }
        }
    }
}

global

routes.MapRouteLowercase("Start", "", new {
    controller = "Home",
    action = "Index"
})

Мне это нравится, и замечательно (как говорится в комментариях), что это действительно помогает улучшить SEO.

1 голос
/ 10 июня 2011

Да, мне пришлось реализовать что-то похожее на вышеописанное.Похоже, это единственный плавный способ сделать это.

Я хотел бы добавить, что кроме того, мы добавили 301 переадресацию, чтобы любой трафик, поступающий из / Upper-Case-Url, был перенаправлен на 301 в / upper-случай-адрес.

0 голосов
/ 19 ноября 2013

Lol, вы, ребята, делаете этот путь слишком тяжело для себя.Просто добавьте это в ваш global.asax application_beginrequest ...

protected void Application_BeginRequest(Object sender, EventArgs e) {
string url = (Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority + HttpContext.Current.Request.Url.AbsolutePath);
if (Regex.IsMatch(url, @"[A-Z]")) {
  PermanentRedirect(url.ToLower() + HttpContext.Current.Request.Url.Query);
}
private void PermanentRedirect(string url) {
  Response.Clear();
  Response.Status = "301 Moved Permanently";
  Response.AddHeader("Location", url);
  Response.End();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...