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
}
- all urls will be caught by the first route and be verified by the constraint.
- if the permalink exists in db the url will be handled by Index action in Page controller.
- 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
Arbitrary-Precision Decimals in C#
How to Initialize a C# Dictionary with Values
Can a Unit Test Project Load the Target Application's App.Config File
Check If Instance Is of a Type
Access to Foreach Variable in Closure Warning
How to Check If a List Is Ordered
Why C# Is Not Allowing Non-Member Functions Like C++
High Quality Jpeg Compression with C#
How to Get the Member to Which My Custom Attribute Was Applied
What's So Bad About Building Xml with String Concatenation
Objects in Scene Dark After Calling Loadscene/Loadlevel
Singleton by Jon Skeet Clarification
Serializing an Object as Utf-8 Xml in .Net
How to Provide Custom Cast Support for My Class
What's the Difference Between Application.Run() and Form.Showdialog()
How to Check If Two Expression<Func<T, Bool>> Are the Same
How to Delete a File Which Is Locked by Another Process in C#