U4-7708 Using a RTE Macro Partial Form (SurfaceController) & Doctype Hijack Controller causes problem with submissions

This commit is contained in:
Shannon
2016-03-10 18:00:14 +01:00
parent 778c7a836b
commit e60e4e52fc
4 changed files with 59 additions and 4 deletions

View File

@@ -0,0 +1,47 @@
using System.IO;
using System.Web.Mvc;
namespace Umbraco.Web.Mvc
{
/// <summary>
/// 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
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
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)
{
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -343,6 +343,7 @@
<Compile Include="Models\Mapping\PropertyGroupDisplayResolver.cs" />
<Compile Include="Models\PublishedContentWithKeyBase.cs" />
<Compile Include="Mvc\ControllerContextExtensions.cs" />
<Compile Include="Mvc\EnsurePartialViewMacroViewContextFilterAttribute.cs" />
<Compile Include="Mvc\IRenderController.cs" />
<Compile Include="Mvc\ModelBindingException.cs" />
<Compile Include="Mvc\RenderIndexActionSelectorAttribute.cs" />

View File

@@ -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<IViewEngine> viewEngines)
{
if (viewEngines == null || viewEngines.Count == 0) return;