Reinoud van Dalen

July 22, 2014

Creating a custom Glass ControllerFactory for Umbraco

In my last post I referred to Route Hijacking. This is a term used by Umbraco and enables you to let Umbraco find your custom controllers based on the RenderMvcController rather than returning the regular RenderMvcController. But I don’t need and don’t want the RenderMvcController so this post explains how you can create your own ControllerFactory which Umbraco will use.

To get a basic understanding of Hijacking Umbraco routes you should read the details on our.umbraco.org: http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers

The way this hijacking works does not reflect how I want to develop my Umbraco applications. And if I think about it for a while I think it would be awesome to be able to create Generic Controllers based on Glass Type models following a convention where the closest type to the current documents type is used.

I want the convention to follow 2 steps:

  1. Find the most suitable controller
  2. Find a DocumentType specific action or fall back to Index method

This way I could create a PageController for all my pages which would look like:

  • PageController : GlassController<BasePage>
    • ActionResult HomePage
    • ActionResult TextPage

And if I feel a pageType deserves it’s own controller then I could add something like:

  • ContactController : GlassController<ContactPage>
    • ActionResult ContactPage

For this to work I need to add 3 things to my project:

  • Generic GlassController as base class
  • Custom GlassControllerFactory to follow the first step of the convention
  • Custom GlassControllerActionInvoker to follow the second step of the convention

Generic Controller

The easiest step is to create a base controller class. To be able to use it in Umbraco MVC we need to implement Controller as well as IRenderMvcController, ending up with something like:

Some description

Custom GlassControllerFactory

This is the trickiest part and there is certainly room for improvement, but this works :)

Inheriting from the UmbracoControllerFactory class, I have overridden 3 methods:

  1. Bool CanHandle: determine if we should be able to resolve a controller
  2. IController CreateController: create and return the most suitable controller
  3. Type GetControllerType: find and return the most suitable controller type

CanHandle

I want to use this factory only if I can resolve a GlassType based on the current content’s DocumentTypeAlias and if no SurfaceController is found. Using an extension method where I can get an UmbracoTypeConfiguration based on a string I can determine if the current page has a Glass Type.

Some description

GetControllerType

Now this is where the magic starts to happen. I collect a list of Glass Types based on the current DocumentTypeAlias. Then I get all the GlassControllers which implement on of the types and sort them based on the index in the Glass Types collection and returning the first. This gives me the most suitable Controller if there is any.

Some description

CreateController

After that magic has happened I create an instance of the controller and manipulate the RouteData so Mvc knows the controller to use, later on we know what method to look for and let Umbraco know not to interfere.

Some description

Custom GlassControllerActionInvoker

I actually already use the custom ActionInvoker in the CreateController method of the Factory because it is an property on a Mvc Controller. The class inherits from Mvc’s ControllerActionInvoker and I override the FindAction method.

In this method I try to get the method using the given actionName parameter (set to the DocumentTypeAlias set in the CreateController method) and if that fails then I try to find an Index method.

Some description

Is that it?

Well, not exactly. The only thing left to do for this to work is letting Umbraco know our ControllerFactory should be taken into consideration. For this I have extended the UmbracoApplication class and in the OnApplicationStarting method I insert my custom ControllerFactory as first to consider before using it’s own factories.

Some description

Then set your Global.asax file to use the extended Application class and you’re good to go. I am currently using this and am very satisfied with the results so far. I get very clean projects and feel it is much closer to an actual Mvc application.

 

TAGS: umbraco glass mvc


Comments
Andrei Avram

Very good article! Do you, by any chance have a public repo containing a fully-working Proof of Concept? I am having a number of issues integrating the code and would like to start using Glass with Umbraco the proper way. Many thanks


Reinoud van Dalen

Hi Andrei, thanks! Even though it has been a while since I've used this, I'd definitely use it again when the chance would present itself. Giving it some more thought I would probably go ahead and make a nuget package of it, but I doubt I will be able to create it anytime soon. If you want I can help you with the issues you ran in to. I'll send you an e-mail so we can discuss it further.