diff --git a/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs b/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs
new file mode 100644
index 0000000000..afd40330ea
--- /dev/null
+++ b/src/Umbraco.Web/Mvc/EnsurePartialViewMacroViewContextFilterAttribute.cs
@@ -0,0 +1,47 @@
+using System.IO;
+using System.Web.Mvc;
+
+namespace Umbraco.Web.Mvc
+{
+ ///
+ /// This is a special filter which is required for the RTE to be able to render Partial View Macros that
+ /// contain forms when the RTE value is resolved outside of an MVC view being rendered
+ ///
+ ///
+ /// The entire way that we support partial view macros that contain forms isn't really great, these forms
+ /// need to be executed as ChildActions so that the ModelState,ViewData,TempData get merged into that action
+ /// so the form can show errors, viewdata, etc...
+ /// Under normal circumstances, macros will be rendered after a ViewContext is created but in some cases
+ /// developers will resolve the RTE value in the controller, in this case the Form won't be rendered correctly
+ /// with merged ModelState from the controller because the special DataToken hasn't been set yet (which is
+ /// normally done in the UmbracoViewPageOfModel when a real ViewContext is available.
+ /// So we need to detect if the currently rendering controller is IRenderController and if so we'll ensure that
+ /// this DataToken exists before the action executes in case the developer resolves an RTE value that contains
+ /// a partial view macro form.
+ ///
+ internal class EnsurePartialViewMacroViewContextFilterAttribute : ActionFilterAttribute
+ {
+ public override void OnActionExecuting(ActionExecutingContext filterContext)
+ {
+ //ignore anything that is not IRenderController
+ if ((filterContext.Controller is IRenderController) == false)
+ return;
+
+ var viewCtx = new ViewContext(
+ filterContext.Controller.ControllerContext,
+ new DummyView(),
+ filterContext.Controller.ViewData, filterContext.Controller.TempData,
+ new StringWriter());
+
+ //set the special data token
+ filterContext.RequestContext.RouteData.DataTokens[Constants.DataTokenCurrentViewContext] = viewCtx;
+ }
+
+ private class DummyView : IView
+ {
+ public void Render(ViewContext viewContext, TextWriter writer)
+ {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs
index 861b872275..0c45c24c4a 100644
--- a/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs
+++ b/src/Umbraco.Web/Mvc/UmbracoViewPageOfTModel.cs
@@ -120,10 +120,9 @@ namespace Umbraco.Web.Mvc
base.InitializePage();
if (ViewContext.IsChildAction == false)
{
- if (ViewContext.RouteData.DataTokens.ContainsKey(Constants.DataTokenCurrentViewContext) == false)
- {
- ViewContext.RouteData.DataTokens.Add(Constants.DataTokenCurrentViewContext, ViewContext);
- }
+ //always ensure the special data token is set - this is used purely for partial view macros that contain forms
+ // and mostly just when rendered within the RTE
+ ViewContext.RouteData.DataTokens[Constants.DataTokenCurrentViewContext] = ViewContext;
}
}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index cb09ef97fd..65fc475c0b 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -343,6 +343,7 @@
+
diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs
index 935d3934a6..93928d0867 100644
--- a/src/Umbraco.Web/WebBootManager.cs
+++ b/src/Umbraco.Web/WebBootManager.cs
@@ -198,6 +198,9 @@ namespace Umbraco.Web
//Wrap viewengines in the profiling engine
WrapViewEngines(ViewEngines.Engines);
+ //add global filters
+ ConfigureGlobalFilters();
+
//set routes
CreateRoutes();
@@ -224,6 +227,11 @@ namespace Umbraco.Web
return this;
}
+ internal static void ConfigureGlobalFilters()
+ {
+ GlobalFilters.Filters.Add(new EnsurePartialViewMacroViewContextFilterAttribute());
+ }
+
internal static void WrapViewEngines(IList viewEngines)
{
if (viewEngines == null || viewEngines.Count == 0) return;