ASP.NETMVC2アプリケーションでURLを正規化するための優れた汎用方法を見つけようとしています。これが私がこれまでに思いついたものです:
// 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 { /* ... */ }
これはすべてかなりうまく機能しているように見えますが、私には次の懸念があります。
CanonicalizeAttribute
この動作を望まない状況を考えるのが難しい場合でも、正規化したいすべてのコントローラー(またはアクションメソッド)にを追加する必要があります。一度に1つのコントローラーではなく、サイト全体でこの動作を実現する方法があるはずです。フィルタに「小文字への強制」ルールを実装しているという事実は間違っているようです。確かに、これをルートURLロジックに組み込む方がよいでしょうが、ルーティング構成でこれを行う方法を考えることはできません。
@"[a-z]*"
コントローラーとアクションパラメーター(およびその他の文字列ルートパラメーター)に制約を追加することを考えましたが、これによりルートが一致しなくなると思います。また、小文字のルールがルートレベルで適用されていないため、大文字が含まれているリンクをページに生成する可能性がありますが、これはかなり悪いようです。
私がここで見落としている明らかな何かがありますか?