11

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 { /* ... */ }

これはすべてかなりうまく機能しているように見えますが、私には次の懸念があります。

  1. CanonicalizeAttributeこの動作を望まない状況を考えるのが難しい場合でも、正規化したいすべてのコントローラー(またはアクションメソッド)にを追加する必要があります。一度に1つのコントローラーではなく、サイト全体でこの動作を実現する方法があるはずです。

  2. フィルタに「小文字への強制」ルールを実装しているという事実は間違っているようです。確かに、これをルートURLロジックに組み込む方がよいでしょうが、ルーティング構成でこれを行う方法を考えることはできません。@"[a-z]*"コントローラーとアクションパラメーター(およびその他の文字列ルートパラメーター)に制約を追加することを考えましたが、これによりルートが一致しなくなると思います。また、小文字のルールがルートレベルで適用されていないため、大文字が含まれているリンクをページに生成する可能性がありますが、これはかなり悪いようです。

私がここで見落としている明らかな何かがありますか?

4

3 に答える 3

20

デフォルトの ASP.NET MVC ルーティングの緩和された性質、文字の大文字と小文字の区別、末尾のスラッシュなどを無視することに関して、私は同じ「かゆみ」を感じました。私のアプリケーション。

Web を高低で検索した後、有用なライブラリが見つからなかったので、自分で作成することにしました。その結果が、ASP.NET ルーティング エンジンを補完するオープン ソース クラス ライブラリであるCanonicalizeです。

NuGet 経由でライブラリをインストールできます。Install-Package Canonicalize

そしてあなたのルート登録で:routes.Canonicalize().Lowercase();

小文字以外にも、いくつかの他の URL 正規化戦略がパッケージに含まれています。ドメインプレフィックスのオンまたはオフを強制し、特定のホスト名、末尾のスラッシュなどを強制します。カスタム URL 正規化戦略を追加することも非常に簡単です。また、「公式」正規化ディストリビューションwwwにさらに戦略を追加するパッチを受け入れることに非常にオープンです。

質問が1年前のものであっても、あなたや他の誰かがこれを参考にしてくれることを願っています:)

于 2011-10-05T15:58:49.187 に答える
6

以下は、MVC2 で正規 URL を作成する方法です。IIS7 書き換えモジュール v2 を使用して、すべての URL を小文字にし、末尾のスラッシュも削除するので、コードからそれを行う必要はありません。(完全なブログ投稿)

次のように、head セクションのマスター ページにこれを追加します。

<%=ViewData["CanonicalURL"] %>
<!--Your other head info here-->

フィルター属性 (CanonicalURL.cs) を作成します。

public class CanonicalURL : ActionFilterAttribute
{
    public string Url { get; private set; }

    public CanonicalURL(string url)
    {
       Url = url;
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        string fullyQualifiedUrl = "http://www.example.com" + this.Url;
        filterContext.Controller.ViewData["CanonicalUrl"] = @"<link rel='canonical' href='" + fullyQualifiedUrl + "' />";
        base.OnResultExecuting(filterContext);
    }
}

アクションからこれを呼び出します。

[CanonicalURL("Contact-Us")]
public ActionResult Index()
 {
      ContactFormViewModel contact = new ContactFormViewModel(); 
      return View(contact);
}

検索エンジンに関するその他の興味深い記事については、Matt Cutts のブログをご覧ください。

于 2010-11-15T21:00:34.670 に答える