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.

Leave a Comment