Cms Routing in MVC

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.

CMS Routing in MVC

Instead of simply using explode() to separate the segments of URL, you could use a set of regular expression pattern.

For example, this following patter would try to match at firsts action, and, if action exists them check if there is controller set before it:

'/(:?(:?\/(?P<controller>[^\/\.,;?\n]+))?\/(?P<action>[^\/\.,;?\n]+))?/'

Most of PHP frameworks use different ways to generate such patterns, with simplified notations. This way you can set which parts for each pattern are mandatory and which optional. And it is also possible to provide fallback values for the optional parts.

That said ...

Before starting to make something so complicated as cms with framework, you might invest some additional time in researching OOP. I would recommend to at least watch lectures from Miško Hevery and Robert C. Martin. Just because you think, that you know how to write a class, does not mean, that you understands object oriented programming.

Update

I have listed few materials in this answer. You might find them useful,

Additionally here are two more lectures, that were not in answer above:

  • Clean Code I: Arguments
  • Clean Code III: Functions

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
}

MVC routing with optional routes

Ok I have a solution, it works for me because 99% of requests need to map to the CMS route but in your case it may not if you have a lot of controllers you need to map to.

I was hoping to find an ideal solution for all but this is merely an ideal in my scenario ...

So assuming you have (like me) only a cms controller and a an accounts controller you can do this:

    routes.MapRoute("Account", "Account/{action}", new { controller = "Account" });

routes.MapRoute(
"Default",
"{*path}",
new { controller = "CMS", action = "GetPage", path = string.Empty }
);

That way only urls starting with "Account" get caught by the first rule, and everything else falls through to the default route and gets handled by the cms controller.

I plan to simply add more routes as I add more controllers. It's not an ideal solution because it could mean i end up with a lot of route mappings in the long term but its a good enough solution to meet my needs.

Hope it helps someone else out there.

Piranha CMS routing issue with ASP.NET MVC

By looking at your config I can see that you have followed the guidelines for setting up Piranha CMS for an existing project by setting passiveMode to true. Let me clarify a bit what this parameter does.

Passive mode is used for applications where you only want to use Piranha CMS as a backend content store and not handle any routing. This means that this parameter effectively turns off all url's to permalinks in the system to not interfere with the existing routes of the application.

If you want to mix your existing application controllers with pages solely generated by Piranha CMS you have to set passiveMode to false which will make the routing for permalinks active again.

Once this is done you will be able to access your pages with or without prefixless permalinks.

Regards

Håkan

MVC4 MapRoute for CMS

You can use:

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

The asterisk indicates that it's a catch-all route. Keep in mind that these routes are extremely greedy, make sure that this stays below any specific routes.

You could also add a route constraint to this route which can determine whether the page exists in the database or something. See this post for more info.

Routing a custom controller in Orchard CMS

Try this:

@using (Html.BeginForm("Send", "Email", new { area = "Your.Module" }, FormMethod.Post, new { id = "contactUsForm" }))

Adding the area is like an extra clause that ensures only your module is searched for a matching controller/action method pair.



Related Topics



Leave a reply



Submit