Basically I have a CMS backend I built using ASP.NET MVC and now I'm moving on to the frontend site and need to be able to load pages from my cms database, based on the route entered.
So if the user enters domain.com/students/information, MVC would look in the pages table to see if a page exists that has a permalink that matches students/information, if so it would redirect to the page controller and then load the page data from the database and return it to the view for display.
So far I have tried to have a catch all route, but it only works for two URL segments, so /students/information, but not /students/information/fall. I can't find anything online on how to accomplish this, so I though I would ask here, before I find and open source ASP.NET MVC cms and dissect the code.
Here is the route configuration I have so far, but I feel there is a better way to do this.
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" }
);
}
If anybody can point me in the right direction on how I would go about loading CMS pages from the database, with up to three URL segments, and still be able to load core pages, that have a controller and action predefined.
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
}
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.