Красивые URL в приложении ASP.NET MVC (routing)

Современный интернет требует красоты не только сайтов, но их внешнего представления (кода, ссылок, оформления, скорости загрузки и анимации). За некоторое время разработки различных сайтов выработал для себя несколько методов работы с ссылками.

Ссылки должны быть в нижнем регистре

Во-первых ссылки в разном регистре менее читабельны, во-вторых они вредят СЕО (т.к. всегда будет кто-то, кто опубликует ссылки измененную). 

Ссылки не должны содержать кирилицы (и других алфавитов)

Аналогично с почтой в зоне рф, глупо делать ссылки, содержащие кирилицу. Во-первых пусть современны браузеры и умеют работать с ними, но далеко не всегда это удобно и практично. Опять же сторона СЕО не всегда чтит кривые ссылки, а поисковые системы умеют индексировать и транслит. Во-вторых это затрудняет копирование и передачу ссылок другим людям.

Результат поиска

Ссылка должна быть всегда в каноническом виде

Все ссылки на сайте должны быть в каноническом виде (всегда в одном и том же). Для этого генерировать ссылки лучше через дополнительный класс. Возможно стоит сделать Handler, который будет проверять вид ссылки (уже даже есть такое правило). Также стоит обратить внимание, как на вашем сайте генерируются ссылки (со сплешем в конце или нет): oxozle.com/link или oxozle.com/link/. С недавнего времени я использую первый вариант, т.к. как мне кажется он более читабельный.

<rule name=“CanonicalHostNameRule1”>
    <match url=“(.*)” />
    <conditions>
        <add input=“{HTTP_HOST}” pattern=“localhost” negate=“true” />
        <add input=“{HTTP_HOST}” pattern=“^oxozle.com$” negate=“true” />
    </conditions>
    <action type=“Redirect” url=“http://oxozle.com/{R:1}" />
</rule>

ASP.NET MVC

Что касается работы со ссылками в ASP.NET MVC были найдены соответствующие решение. Обо всем по порядку. Ссылки в нижнем регистре, если используется стандартный механизм генерации ссылок (Action…), класс LowercaseRoute:

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)
{
    var path = base.GetVirtualPath(requestContext, values);

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

    return path;
}

}

Для более удобной записи путей (routing) в RouteConfig был найден следующий класс:

public static class RouteCollectionExtension
{
    public static Route MapLowerCaseRoute(this RouteCollection routes, string url, object defaults)
    {
        return routes.MapLowerCaseRoute(url, defaults, null);
    }

public static Route MapLowerCaseRoute(this RouteCollection routes, string url, object defaults, object constraints)
{
    Route route = new LowercaseRoute(url, new MvcRouteHandler())
    {
        Defaults = new RouteValueDictionary(defaults),
        Constraints = new RouteValueDictionary(constraints)
    };

    routes.Add(null, route);

    return route;
}   

}

Он позволяет вместо стандартной длинной, неудобной записи вида

routes.MapRoute(
    name: “Default”,
    url: “{controller}/{action}/{id}”,
    defaults: new { controller = “Home”, action = “Index”, id = UrlParameter.Optional }
);

иметь настройки вида:

routes.MapLowerCaseRoute(“ajax/{action}/{id}”, new { controller = “Ajax”, action = “”, id = UrlParameter.Optional });
routes.MapLowerCaseRoute(“pages/{action}/{id}”, new { controller = “Pages”, action = “”, id = UrlParameter.Optional });
routes.MapLowerCaseRoute(“account/{action}/{id}”, new { controller = “Account”, action = “”, id = UrlParameter.Optional });
routes.MapLowerCaseRoute(“{year}/{month}/{day}/{slug}”, new { controller = “Blog”, action = “ShowPost” });

Для генерации ссылок я использую обычный класс, который знает как устроены ссылки (и если я решу изменить, мне нужно будет изменить только этот класс + настройку редиректа). Вот пример такого класса:

public static class Links
{
    public static string Login()
    {
        return “/login”;
    }

public static string Page(string slug)
{
    return "/" + slug.ToLower();
}

#region Blog

public static string BlogPostsByTag(int id)
{
    return "/tag/" + id;
}

public static string Post(this BlogPost post)
{
    return "/" + post.DatePublish.ToString("yyyy\\/MM\\/dd") + "/" + post.Slug;
}
#endregion

public static string Feed()
{
    return "/feed";
}

}

Комментарии

comments powered by Disqus