Как правильно канонизировать URL-адрес в ASP.NET MVC приложение?

Я пытаюсь найти хороший универсальный способ канонизации URL-адресов в приложении ASP.NET MVC 2. Вот что я придумал на данный момент:

// Using an authorization filter because it is executed earlier than other filters
public class CanonicalizeAttribute : AuthorizeAttribute
{
    public bool ForceLowerCase { get;set; }

    public CanonicalizeAttribute()
        : base()
    {
        ForceLowerCase = true;
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        RouteValueDictionary values = ExtractRouteValues(filterContext);
        string canonicalUrl = new UrlHelper(filterContext.RequestContext).RouteUrl(values);
        if (ForceLowerCase)
            canonicalUrl = canonicalUrl.ToLower();

        if (filterContext.HttpContext.Request.Url.PathAndQuery != canonicalUrl)
            filterContext.Result = new PermanentRedirectResult(canonicalUrl);
    }

    private static RouteValueDictionary ExtractRouteValues(AuthorizationContext filterContext)
    {
        var values = filterContext.RouteData.Values.Union(filterContext.RouteData.DataTokens).ToDictionary(x => x.Key, x => x.Value);
        var queryString = filterContext.HttpContext.Request.QueryString;
        foreach (string key in queryString.Keys)
        {
            if (!values.ContainsKey(key))
                values.Add(key, queryString[key]);
        }
        return new RouteValueDictionary(values);
    }
}

// Redirect result that uses permanent (301) redirect
public class PermanentRedirectResult : RedirectResult
{
    public PermanentRedirectResult(string url) : base(url) { }

    public override void ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Response.RedirectPermanent(this.Url);
    }
}

Теперь я могу размечать свои контроллеры следующим образом:

[Canonicalize]
public class HomeController : Controller { /* ... */ }

Кажется, все это работает достаточно хорошо, но у меня есть следующие проблемы:

  1. Мне все еще нужно добавить CanonicalizeAttribute для каждого контроллера (или метода действия), который я хочу канонизировать, когда сложно представить ситуацию, в которой я не хочу такого поведения. Похоже, что должен быть способ добиться такого поведения для всего сайта, а не для одного контроллера за раз.

  2. Тот факт, что я реализую правило «принудительно переводить в нижний регистр» в фильтре, кажется неправильным. Конечно, было бы лучше каким-то образом включить это в логику URL-адреса маршрута, но я не могу придумать способ сделать это в моей конфигурации маршрутизации. Я подумал о добавлении @ "[az] *" ограничений к параметрам контроллера и действия (а также к любым другим параметрам строкового маршрута), но я думаю, что это приведет к тому, что маршруты не будут сопоставлены. Кроме того, поскольку правило нижнего регистра не применяется на уровне маршрута, на моих страницах можно создавать ссылки с прописными буквами, что кажется довольно плохим.

Есть ли что-то очевидное? Я здесь вы не видите?

10
задан Lance Roberts 19 February 2013 в 23:45
поделиться