Hijacking Umbraco routes
DISCLAIMER!
This blog post relates to the latest source code of Umbraco v5 and will not work in Umbraco 5.0.0. Unfortunately due to my own mistakes which I take full credit for (#h5is) in fixing a last minute bug in 5.0.0 I actually broke this functionality for the release. So the following blog post relates to upcoming releases of Umbraco 5.x or if you are using the latest source code in Mercurial.
By default all of the front end routing is executed via the UmbracoController Index Action which should work fine for most people. However, in some cases people may want complete control over this execution and may want their own Action to execute. Some reasons for this may be: to control exactly how views are rendered, custom/granular security for certain pages/templates or to be able to execute any custom code in the controller that renders the front end. The good news is that this is completely possible, in fact this was one of the first features implemented in V5 all the way back in 2010!
This process is all about convention and it's really simple. It's easiest to demonstrate with an example : let's say you have a document type called 'Home'. You can create a custom locally declared controller in your MVC web project called 'HomeController' and ensure that it inherits from Umbraco.Cms.Web.Mvc.Controllers.UmbracoController and now all pages that are of document type 'Home' will be routed through your custom controller! Pretty easy right :-)
OK so let's see how we can extend this concept. In order for you to run some code in your controller you'll need to override the Index Action. Here’s a quick example:
public class HomeController : UmbracoController
{
public override ActionResult Index(IUmbracoRenderModel model)
{
//Do some stuff here, the return the base method
return base.Index(model);
}
}
Now you can run any code that you want inside of that Action. To further extend this, we've also allowed routing to different Actions based on the Template that is being rendered. By default only the Index Action exists which will execute for all requests of the corresponding document type. However, if the template being rendered is called 'HomePage' and you have an Action on your controller called 'HomePage' then it will execute instead of the Index Action. As an example, say we have a Home Document Type which has 2 allowed Templates: ‘HomePage’ and ‘MobileHomePage’ and we only want to do some custom stuff for when the ‘MobileHomePage’ Template is executed:
public class HomeController : UmbracoController
{
public ActionResult MobileHomePage(IUmbracoRenderModel model)
{
//Do some stuff here, the return the base Index method
return base.Index(model);
}
}
So here's how the mapping works:
- Document Type name = controller name
- Template name = action name, but if no action matches or is not specified then the 'Index' action will be executed.
In the near future we will allow setting a custom default controller to execute for all requests instead of the standard UmbracoController. Currently you'd have to create a controller for every document type to have a customer controller execute for all requests.
There's probably a ton of uses for hijacking an Umbraco request that we haven't thought of yet. Now that you know how to do it I'm sure plenty of new techniques will be invented.
Happy coding! :)