Using Umbraco Route Hijacking and posting to it

Simple usage of Umbraco route hijacking allows you to add more features to your website and respond to your viewers request in a better way. It will also allow you to use custom models and populate them before the view gets called/rendered.

To start with route hyjacking you need to create a document type for your page, the name of the document type is important because your controller will need to have the same name as the document type in order for the Umbraco routing engine to pick it up.

Tip: Say we create a document type called NewsLister, we would need to create a controller called NewsListerController within a class file called anything, I'll call mine, NewsListerController.cs.

Now you need to create a template that the document type will allow, I'll also call my template NewsLister.

Tip: The name of the template only matters if you're planning on handling multiple templates from one controller.

Assign your template to the document type and create a page in the content area that used your new document type and template.

Now, in NewsListerController.cs, add the following code:

public class NewsListerController : RenderMvcController
{
    // The default action to render the front-end view, will populate the model and return the view.
    public override ActionResult Index(RenderModel objModel)
    {
        // Construct a new model to work with.
        MyModel objModel = new MyModel() { MyVariable = "Some value." };

        // Return the search results view with the populated model. (The template dropdown becomes irrelevent in a hybrid controller.)
        return CurrentTemplate(objModel);
    }
}

Now all you need to do is make sure that your template has the following at the top of the file:

@inherits Umbraco.Web.Mvc.UmbracoViewPage

The index method is called if a method does not exist with the same name as the template used, so to do something else with a different template, just add another method witht hat templates name and add some similar code.

Tip: Replace MyModel with the name of the class that will contain the data you need to use in your page.

See the following code as an example of a model you could use.

// Minimal routing model, contains a parameterless constructor so that it can be used for postbacks.
public class MyModel : RenderModel
{
    // Parameterless constructor to handle postbacks, will call the main constructor.
    public MyModel() : this(UmbracoContext.Current.PublishedContentRequest.PublishedContent) { }
        
    // Main constructor.
    public MyModel(IPublishedContent content) : base(content) { }

    public String MyVariable { get; set; }
}

That's it!

You might run into an issue some people get where you want to post to the page that's been rendered via a route hijack, but the controller is of type RenderMvcController and not SurfaceController. Don't worry I've got you covered, add the following class to your website somewhere and extend your controller with it instead of the RenderMvcController, as it implements both SurfaceController and RenderMvcController, you will be able to use route hijacking on and post a form to the same controller, pretty neat eh?

// The base route controller allows the use of a surface controller and a rendermvc controller in one.
// This allows us to create a controller that can be used for both route hyjacking and and form posting.
public class BaseRouteController : SurfaceController, IRenderMvcController
{
    // The default action to render the front-end view.
    public virtual ActionResult Index(RenderModel model)
    {
        // Just return the chosen template from the back office.
        return CurrentTemplate(model);
    }

    // Checks to make sure the physical view file exists on disk.
    protected bool EnsurePhysicalViewExists(string template)
    {
        var result = ViewEngines.Engines.FindView(ControllerContext, template, null);
        if (result.View == null)
        {
            LogHelper.Warn("No physical template file was found for template " + template);
            return false;
        }
        return true;
    }

    // Returns an ActionResult based on the template name found in the route values and the given model.
    // If the template found in the route values doesn't physically exist, then an empty ContentResult will be returned.
    protected ActionResult CurrentTemplate(T model)
    {
        var template = ControllerContext.RouteData.Values["action"].ToString();
        if (!EnsurePhysicalViewExists(template))
        {
            return Content("");
        }
        return View(template, model);
    }
}

See more on this, here: https://our.umbraco.org/documentation/reference/routing/custom-controllers


Published at

Tags: Umbraco

Luke Alderton

Comments

phuong
Thanks for this. Was really helpful when i wanted to decouple my views from umbraco. Typo in BaseRouteController - you need to specify the protected ActionResult CurrentTemplate < T > (T model) - brilliant class!
15/11/2016
Josh
@phuong - Thank you for clarifying that!!!
14/01/2019
Share with
Tags
Latest Comments
By Mark Gentry on Windows Server 2019 - Change product key does nothing
20 Aug 2021, 03:30 AM
By Cathy on In-Place Upgrade for a Windows Server domain controller
31 Jul 2021, 18:28 PM
By Mr. Greymatter on Raspberry Pi - Running Java app on Raspbian
16 Feb 2021, 07:35 AM
By Mikko Seittenranta on Xamarin Forms multiple instances of same app open
16 Feb 2021, 04:34 AM
By Andrew on Auto/Custom height on Xamarin Forms WebView for Android and iOS
22 Jan 2021, 22:15 PM
By Nick on Raspberry Pi - Running Java app on Raspbian
14 Oct 2020, 19:37 PM
By Ivan on Fixed: Value cannot be null Parameter Name: source
15 Sep 2020, 19:47 PM
By Anand on Raspberry Pi - Bluetooth using Bluecove on Raspbian
7 Sep 2020, 16:53 PM
Categories
App Development
Event
Game Development
Mapping
Modelling
Programming
Review
Robotics
Tutorial
Web Development