Tuesday, April 5, 2016

Multiple static Sitecore MVC forms

Multiple Sitecore MVC forms

Reinoud Van Dalen wrote a famous blog post over a year ago about multiple Sitecore MVC forms on a single page. His fix was based on some good work from Kevin Brechbühl and it helped us a lot. But recently we bumped into an issue on a Sitecore 8.1 project with mvc forms that were added on a more static way with @Html.Sitecore.Rendering().

Html.Sitecore.Rendering()

We created controller renderings for our forms in Sitecore and used their id's to display the statically bound rendering using @Html.Sitecore.Rendering(). We noticed that when we add such a rendering with Sitecore in a placeholder the code worked fine and the RenderingToken was set. But once the same rendering was placed statically, the CurrentRendering.UniqueId was an empty guid.

One could wonder why we place our forms statically in a View but we have our reasons. The views containing the static bound form-renderings can be placed in placeholders or also statically, that does not make a difference - the UniqueId stays empty.

A fix

We fixed this by making a small change to the original code:

RenderingToken


public static class SitecoreHelperExtensions
{
    public static MvcHtmlString RenderingToken(this SitecoreHelper helper)
    {
        if (helper?.CurrentRendering == null)
        {
            return null;
        }

        var tagBuilder = new TagBuilder("input");
        tagBuilder.Attributes["type"] = "hidden";
        tagBuilder.Attributes["name"] = "uid";
        tagBuilder.Attributes["value"] = helper.CurrentRendering.UniqueId +
                                            helper.CurrentRendering.RenderingItemPath;

        return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.SelfClosing));
    }
}

ValidRenderingTokenAttribute


[AttributeUsage(AttributeTargets.Method)]
public sealed class ValidRenderingTokenAttribute : ActionMethodSelectorAttribute
{
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        var rendering = RenderingContext.CurrentOrNull;
        if (rendering == null || controllerContext == null)
        {
            return false;
        }

        var id = controllerContext.HttpContext.Request.Form["uid"];
        return id.Equals(rendering.Rendering.UniqueId + rendering.Rendering.RenderingItemPath, StringComparison.OrdinalIgnoreCase);
    }
}

The only thing we did was adding the RenderingItemPath to the hidden token.
The "bonus" from Reinouds code to be able to include the same form multiple times on a page still exists as long as the form is added with Sitecore on a placeholder for at least all but one occasions. It is not possible to add the same form twice statically though.


Thanks again to Reinoud for sharing his code on multiple mvc forms - hopefully this little addition can help people who need to add forms statically.