Dynamic Routes from Database for ASP.NET MVC Cms

Dynamic Routes from database for ASP.NET MVC CMS

You can use a constraint to decide whether to override the default routing logic.

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;
}
}

use it in route definition like,

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 }
);

Now if you have an 'Index' action in 'Page' Controller like,

public ActionResult Index(string permalink)
{
//load the content from db with permalink
//show the content with view
}
  1. all urls will be caught by the first route and be verified by the constraint.
  2. if the permalink exists in db the url will be handled by Index action in Page controller.
  3. if not the constraint will fail and the url will fallback to default route(i dont know if you have any other controllers in the project and how you will decide your 404 logic).

EDIT

To avoid re querying the cms page in the Index action in Page controller, one can use the HttpContext.Items dictionary, like

in the constraint

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;

then in the action,

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

hope this helps.

MVC routing for CMS pages

Add your "catch all" route on top of "default" route and add a route constrain to path like this:

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

routes.MapRoute(
"Static page",
"{*path}",
new { controller = "Content", action = "StaticPage" }
new { path = new PathConstraint() });

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

PathConstraint should derive from from IRouteConstraint interface and can be something like this:

public class PathConstraint: IRouteConstraint
{

public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (values[parameterName] != null)
{
var permalink = values[parameterName].ToString();
//gather all possible paths from database
//and check if permalink is any of them
//return true or false
return database.GetPAths().Any(p => p == permalink);
}
return false;
}
}

So if "path" is not one of your pages paths, PathConstrain will not be satisified and "Static page" route will be skiped and pass to next route.

Dynamic Routes from sql database

You can just add a route something like this in Startup.cs

routes.MapRoute(
name: "cmsroute",
template: "{slug}"
, defaults: new { controller = "Cms", action = "GetContent" }
);

Note also rather than build your own new cms you might find my project cloudscribe.SimpleContent is useful to you, even if you do want to build your own you can study the code and get ideas on how to do things

Dynamically routing using routes from a database

In your Index.cshtml page replace @page with @page "/{name?}". So you should have something like below:

@page "/{name?}"
@model MyApplicationNamespace.Pages.IndexModel

After that change the Index.cshtml.cs like below:

public IActionResult OnGet(string name)
{
// Here you check if name parameter given trough the URL an check with its existence in the database. if yes, then `return Page();`
// Otherwise just redirect to the error page or something to let the user know what happened by using `return RedirectToPage("TheErrorPage");`
}

Dynamic/Editable MVC routes stored in the database for blog engine

I'd declare your default route as normal, and then read the database and call the same methods, but rather than passing in hard coded strings, pass in the values from the database:

foreach(RouteDetails routeDetails in routesFromDatabase)
{
routes.MapRoute(
routeDetails.Name,
routeDetails.Route,
routeDetails.Defaults);
}

You'll need to map the tables properly and populate the fields in the imagined object 'RouteDetails', including the Defaults dictionary (which would probably be the most complicated).

You can find a couple of examples here:

  • asp.net mvc: store routes in the
    database
  • Editable MVC Routes Apache Style


Related Topics



Leave a reply



Submit