6

ユーザーが独自のSEOURL(Wordpressなど)を作成できるように、CMSのページにカスタムスラッグを作成したいと思います。

私はこれをRubyonRailsとPHPフレームワークで、404ルートを「悪用」することで行っていました。このルートは、要求されたコントローラーが見つからなかったときに呼び出され、ユーザーを動的ページコントローラーにルーティングしてスラッグを解析できるようにしました(ページが見つからなかった場合は、そこから実際の404にリダイレクトしました)。このように、データベースは要求されたスラッグをチェックするためだけに照会されました。

ただし、MVCでは、キャッチオールルートは、ルートがデフォルトルートのに適合しない場合にのみ呼び出されます/{controller}/{action}/{id}

カスタムスラッグを解析できるようにするために、RouteConfig.csファイルを変更しました。

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        RegisterCustomRoutes(routes);

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { Controller = "Pages", Action = "Index", id = UrlParameter.Optional }
        );
    }

    public static void RegisterCustomRoutes(RouteCollection routes)
    {
        CMSContext db = new CMSContext();
        List<Page> pages = db.Pages.ToList();
        foreach (Page p in pages)
        {
            routes.MapRoute(
                name: p.Title,
                url: p.Slug,
                defaults: new { Controller = "Pages", Action = "Show", id = p.ID }
            );
        }
        db.Dispose();
    }
}

これで私の問題は解決しPagesますが、リクエストごとにテーブルを完全に照会する必要があります。オーバーロードされたshowメソッド(public ViewResult Show(Page p))が機能しなかったため、ページIDしか渡せないため、もう一度ページを取得する必要があります。

  1. 私の問題を解決するためのより良い方法はありますか?
  2. ページIDの代わりにPageオブジェクトをShowメソッドに渡すことは可能ですか?
4

1 に答える 1

4

ルート登録コードがそのまま機能する場合でも、ルートが起動時にのみ静的に登録されるという問題があります。新しい投稿が追加されるとどうなりますか? アプリ プールを再起動する必要がありますか?

URL の SEO スラッグ部分を含むルートを登録し、ルックアップでスラッグを使用することができます。

RouteConfig.cs

routes.MapRoute(
    name: "SeoSlugPageLookup",
    url: "Page/{slug}",
    defaults: new { controller = "Page", 
                    action = "SlugLookup",
                  });

PageController.cs

public ActionResult SlugLookup (string slug)
{
    // TODO: Check for null/empty slug here.

    int? id = GetPageId (slug);

    if (id != null) {    
        return View ("Show", new { id });
    }

    // TODO: The fallback should help the user by searching your site for the slug.
    throw new HttpException (404, "NotFound");
}

private int? GetPageId (string slug)
{
    int? id = GetPageIdFromCache (slug);

    if (id == null) {
        id = GetPageIdFromDatabase (slug);

        if (id != null) {
            SetPageIdInCache (slug, id);
        }
    }

    return id;
}

private int? GetPageIdFromCache (string slug)
{
    // There are many caching techniques for example:
    // http://msdn.microsoft.com/en-us/library/dd287191.aspx
    // http://alandjackson.wordpress.com/2012/04/17/key-based-cache-in-mvc3-5/
    // Depending on how advanced you want your CMS to be,
    // caching could be done in a service layer.
    return slugToPageIdCache.ContainsKey (slug) ? slugToPageIdCache [slug] : null;
}

private int? SetPageIdInCache (string slug, int id)
{
    return slugToPageIdCache.GetOrAdd (slug, id);
}

private int? GetPageIdFromDatabase (string slug)
{
    using (CMSContext db = new CMSContext()) {
        // Assumes unique slugs.
        Page page = db.Pages.Where (p => p.Slug == requestContext.Url).SingleOrDefault ();

        if (page != null) {
            return page.Id;
        }
    }

    return null;
}

public ActionResult Show (int id)
{
    // Your existing implementation.
}

(参考までに:コードはコンパイルもテストもされていません-現在、開発環境を利用できません。疑似コードとして扱います;)

この実装では、サーバーの再起動ごとにスラッグの検索が 1 回行われます。起動時にキーと値のスラッグから ID へのキャッシュを事前設定することもできるため、既存のすべてのページ ルックアップが安価になります。

于 2012-07-15T23:01:51.547 に答える