web-dev-qa-db-ja.com

ASP.NET MVC CMSのデータベースからの動的ルート

基本的に、ASP.NET MVCを使用して構築したCMSバックエンドがあり、現在はフロントエンドサイトに移動しており、入力したルートに基づいてcmsデータベースからページをロードできるようにする必要があります。

したがって、ユーザーがdomain.com/students/informationを入力すると、MVCはページテーブルを調べて、学生/情報に一致するパーマリンクを持つページが存在するかどうかを確認し、存在する場合はページコントローラーにリダイレクトしてからページを読み込みますデータベースからデータを取得し、表示のためにビューに返します。

これまでのところ、すべてのルートをキャッチしようとしましたが、2つのURLセグメントでのみ機能するため、/ students/informationではなく、/ students/information/fallでは機能します。私はこれを達成する方法についてオンラインで何も見つけられないので、ASP.NET MVC cmsを見つけてオープンソースにしてコードを分析する前に、ここで尋ねたいと思います。

ここに私がこれまで持っているルート構成がありますが、これを行うにはもっと良い方法があると感じています。

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

        // Default route to handle core pages
        routes.MapRoute(null,"{controller}/{action}/{id}",
                        new { action = "Index", id = UrlParameter.Optional },                  
                        new { controller = "Index" }
        );

        // CMS route to handle routing to the PageController to check the database for the route.


        var db = new MvcCMS.Models.MvcCMSContext();
        //var page = db.CMSPages.Where(p => p.Permalink == )
        routes.MapRoute(
            null,
            "{*.}",
            new { controller = "Page", action = "Index" }
        );          
    }

誰かが私にデータベースからCMSページをロードする方法について正しい方向に向けることができれば、最大3つのURLセグメントで、コントローラーとアクションが事前に定義されているコアページをロードすることができます。

66
Carl Weis

制約を使用して、デフォルトのルーティングロジックをオーバーライドするかどうかを決定できます。

public class CmsUrlConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        var db = new MvcCMS.Models.MvcCMSContext();
        if (values[parameterName] != null)
        {
            var permalink = values[parameterName].ToString();
            return db.CMSPages.Any(p => p.Permalink == permalink);
        }
        return false;
    }
}

次のようなルート定義で使用します

routes.MapRoute(
    name: "CmsRoute",
    url: "{*permalink}",
    defaults: new {controller = "Page", action = "Index"},
    constraints: new { permalink = new CmsUrlConstraint() }
);

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

「ページ」コントローラーに「インデックス」アクションがある場合、

public ActionResult Index(string permalink)
{
    //load the content from db with permalink
    //show the content with view
}
  1. すべてのURLは最初のルートでキャッチされ、制約によって検証されます。
  2. dbにパーマリンクが存在する場合、URLはページコントローラーのインデックスアクションによって処理されます。
  3. そうでない場合、制約は失敗し、URLはデフォルトルートにフォールバックします(プロジェクトに他のコントローラーがあるかどうか、および404ロジックをどのように決定するかはわかりません)。

[〜#〜] edit [〜#〜]

IndexコントローラーのPageアクションでcmsページを再クエリしないようにするには、HttpContext.Items辞書、など

制約内

var db = new MvcCMS.Models.MvcCMSContext();
if (values[parameterName] != null)
{
    var permalink = values[parameterName].ToString();
    var page =  db.CMSPages.Where(p => p.Permalink == permalink).FirstOrDefault();
    if(page != null)
    {
        HttpContext.Items["cmspage"] = page;
        return true;
    }
    return false;
}
return false;

その後、アクションで、

public ActionResult Index(string permalink)
{
    var page = HttpContext.Items["cmspage"] as CMSPage;
    //show the content with view
}

お役に立てれば。

120
shakib

カスタムルーターの処理を必要としない、よりシンプルなアプローチを使用します。いくつかのオプションパラメータを処理する単一/グローバルコントローラを作成し、それらのパラメータを必要に応じて処理します。

//Route all traffic through this controller with the base URL being the domain 
[Route("")]
[ApiController]
public class ValuesController : ControllerBase
{
    //GET api/values
    [HttpGet("{a1?}/{a2?}/{a3?}/{a4?}/{a5?}")]
    public ActionResult<IEnumerable<string>> Get(string a1 = "", string a2 = "", string a3 = "", string a4 = "", string a5 = "")
    {
        //Custom logic processing each of the route values
        return new string[] { a1, a2, a3, a4, a5 };
    }
}

Domain.com/test1/test2/test3でのサンプル出力

["test1","test2","test3","",""]
0
Kon Rad