U4-2460 - Umbraco.RenderTemplate() returns exception text when called from within a SurfaceController method

Created by Robert Foster 04 Jul 2013, 06:57:24 Updated by Sebastiaan Janssen 09 Jul 2013, 14:08:24

I have a controller that looks like this:

public class FormController : SurfaceController { [ChildActionOnly] public ActionResult ContactUs() { HtmlHelper.UnobtrusiveJavaScriptEnabled = true; HtmlHelper.ClientValidationEnabled = true;

        return PartialView(new ContactModel());
    }

    [HttpPost]
    public ActionResult HandleContactUs(ContactModel model)
    {
        if (ModelState.IsValid)
        {
            string errorMsg = string.Empty;

            var template = Umbraco.RenderTemplate(model.HtmlTemplateId /*1112*/);

        }
        else
        {
            TempData["ContactFormSuccess"] = false;
        }

        // We want to return to the actual page.
        return RedirectToCurrentUmbracoPage();

    }

}

My Corresponding View looks like this: @inherits Umbraco.Web.Mvc.UmbracoViewPage

@using (Html.BeginUmbracoForm("HandleContactUs")) { @Html.ValidationSummary(true)
  1. @Html.TextBoxFor(model => model.Name, new { placeholder = "* Name" }) @Html.ValidationMessageFor(model => model.Name)
  2. @Html.TextBoxFor(model => model.Company, new { placeholder = "Company" }) @Html.ValidationMessageFor(model => model.Company)
  3. @Html.TextBoxFor(model => model.Phone, new { placeholder = "* Phone" }) @Html.ValidationMessageFor(model => model.Phone)
  4. @Html.TextBoxFor(model => model.Email, new { placeholder = "* Email" }) @Html.ValidationMessageFor(model => model.Email)
  5. @Html.TextAreaFor(model => model.Comments, new { placeholder = "* Comments" }) @Html.ValidationMessageFor(model => model.Comments)

}

When I submit the form and try to render the template for the passed in content node I get:

I can view the node directly and the template is rendered correctly if I browse to it.

This is a major show stopper as I need a way to render the template in a view controller.

Comments

Robert Foster 04 Jul 2013, 08:36:02

It seems this line is the culprit (Line 141 in Umbraco-CMS / src / Umbraco.Web / Templates / TemplateRenderer.cs): routeDef.Controller.ControllerContext = new ControllerContext(requestContext, routeDef.Controller); because the routeDef.Controller is always null.

I have a tentative fix for it (however I'm not sure it belongs in this method) by adding in the logic to set up the Controller if it's missing right before the call set up the ControllerContext: if (routeDef.Controller == null) { // Get the factory and controller and create a new instance of the controller var factory = ControllerBuilder.Current.GetControllerFactory(); var controller = factory.CreateController(requestContext, routeDef.ControllerName) as ControllerBase;

                    // Store the controller
                    routeDef.Controller = controller;
                }

This works, but somehow I'm not sure it belongs here...


Robert Foster 04 Jul 2013, 08:42:08

Alternatively perhaps we need to somehow use the UmbracoMVCHandler (where the code snippet above came from originally) so that the controller gets set up correctly in the Route Definition?


Shannon Deminick 05 Jul 2013, 04:15:27

Hi Robert, I've fixed this in revision: 048480d5be9ff1fa6b6681608b5453169e8ab7ba

When i first made the RenderTemplate method I realized that other MVC parts would never work because we were just rendering the output of the view, it wasn't executing the full MVC pipeline to get the result. I've changed it now to ensure that the whole MVC pipeline is executed to get the view result.

Also, your solution above would work (to render the view result) and the reason why Controller is null is because of another fix for IoC which introduced the UmbracoMvcHandler. So this probably did work before until that other fix was applied.

Anyways, the new fix should be best for everything.


Sandor Voordes 05 Jul 2013, 20:29:41

Hi Dominick. Does this also make it possible to call RenderTemplate from a application.PreRequestHandlerExecute event in a module?

More important: Does this fix automatically trickle down into the umbraco v6.0.* version as a new revision?


Shannon Deminick 08 Jul 2013, 00:03:40

@Sandor, I hightly doubt calling RenderTemplate from PreRequestHandlerExecute will work, especially if you are rendering an MVC template. The route definition that is required for an MVC page to execute is added in the RenderRouteHandler which I'm pretty sure is executed by the ASP.Net MvcHandler which of course means a request handler needs to be assigned. ... but you can always try :)

6.1 is stable so there are currently no planned patches for 6.0.x at this stage so this fix will remain in the 6.1.3 release.


Sandor Voordes 08 Jul 2013, 09:20:51

@Dominick: Thanks for the answer. Bit surprised though because it did work on a 4.11.8 project that also used MVC. What's different in the MVC setup for V6.

As for the stability of versions: I understood from one of the HQ people at CodeGarden that there was a new way of versioning now where bugs fixed in the latest would automatically be merged in previous minor releases. Are you stating that this is not the case? If so we are forced to switch to 6.1.3 I guess.


Shannon Deminick 08 Jul 2013, 09:27:53

If it did work in 4.11.8, then give it a try!

But the way that it was doing it before was just rendering the string output of a view, it wasn't processing the template by using the MVC engine so if people had hijacked routes, custom controllers, child actions, etc... inside of their view it would not have worked. So it may have worked before because it wasn't really working after all.

Not sure who told you that from the HQ but it's more the opposite of that. Any fixes in smaller versions get automatically merged up to bigger versions. If there's specific patches that need to be applied to earlier versions from larger versions that has to be done manually and generally is only required if there is a major issue found in the smaller version like a security issue.

The next release wont be out for a while and I'll need to chat to Sebastian since there might need to be a case for releasing another 6.0.x due to some other issues recently found. The upgrade process to 6.1.3 is seamless which is why we're only going to patch 6.0.x if there are major issues.


Robert Foster 08 Jul 2013, 10:47:25

@Sandor I'd simply upgrade to the latest 6.1.x in this case (waiting for the next release to get the patch of course). No breaking changes to 6.0.x and you get the benefit of other fixes that since that release of course.

If you need to continue on the 6.0.x branch you'll need to download the source and patch it yourself, which isn't difficult, and compiling is straightforward; just copy the dlls from the bin directory of the Umbraco.Web.UI project and you're done.


Sebastiaan Janssen 09 Jul 2013, 14:08:24

@Sandor Just to clarify @Shannon's comment: We'll only patch 6.0.x if there's security issues found, but we are not going to have two versions with the same major version number from now on (so: when we release v7 we'll still have v6 releases, just like we did with v4 and v6. But no more minor versions like 6.0.x and 6.1.x versions will be released simultaneously). As Shannon and Robert have mentioned, an upgrade to 6.1.3 is straight forward and there are no breaking changes and you get the benefits of the other updates we've been doing.


Priority: Normal

Type: Bug

State: Fixed

Assignee: Shannon Deminick

Difficulty: Normal

Category:

Backwards Compatible: True

Fix Submitted: Inline code

Affected versions: 6.1.1, 6.1.2

Due in version: 6.1.3

Sprint:

Story Points:

Cycle: