diff --git a/src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs b/src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs
new file mode 100644
index 0000000000..a672fdfd3c
--- /dev/null
+++ b/src/Umbraco.Web.Common/Controllers/ProxyViewDataFeature.cs
@@ -0,0 +1,20 @@
+using Microsoft.AspNetCore.Mvc.ViewFeatures;
+
+namespace Umbraco.Web.Common.Controllers
+{
+ ///
+ /// A request feature to allowing proxying viewdata from one controller to another
+ ///
+ public sealed class ProxyViewDataFeature
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ProxyViewDataFeature(ViewDataDictionary viewData) => ViewData = viewData;
+
+ ///
+ /// Gets the
+ ///
+ public ViewDataDictionary ViewData { get; }
+ }
+}
diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs
index 2359d6d13c..48fe50facc 100644
--- a/src/Umbraco.Web.Common/Controllers/RenderController.cs
+++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
@@ -149,6 +150,20 @@ namespace Umbraco.Web.Common.Controllers
break;
case UmbracoRouteResult.Success:
default:
+
+ // Check if there's a ProxyViewDataFeature in the request.
+ // If there it is means that we are proxying/executing this controller
+ // from another controller and we need to merge it's ViewData with this one
+ // since this one will be empty.
+ ProxyViewDataFeature saveViewData = HttpContext.Features.Get();
+ if (saveViewData != null)
+ {
+ foreach (KeyValuePair kv in saveViewData.ViewData)
+ {
+ ViewData[kv.Key] = kv.Value;
+ }
+ }
+
// continue normally
await next();
break;
diff --git a/src/Umbraco.Web.Website/ActionResults/RedirectToUmbracoPageResult.cs b/src/Umbraco.Web.Website/ActionResults/RedirectToUmbracoPageResult.cs
index 3d97b893c3..8a106c0846 100644
--- a/src/Umbraco.Web.Website/ActionResults/RedirectToUmbracoPageResult.cs
+++ b/src/Umbraco.Web.Website/ActionResults/RedirectToUmbracoPageResult.cs
@@ -16,7 +16,7 @@ namespace Umbraco.Web.Website.ActionResults
///
/// Redirects to an Umbraco page by Id or Entity
///
- public class RedirectToUmbracoPageResult : IActionResult
+ public class RedirectToUmbracoPageResult : IActionResult, IKeepTempDataResult
{
private IPublishedContent _publishedContent;
private readonly QueryString _queryString;
@@ -122,19 +122,15 @@ namespace Umbraco.Web.Website.ActionResults
throw new ArgumentNullException(nameof(context));
}
- var httpContext = context.HttpContext;
- var ioHelper = httpContext.RequestServices.GetRequiredService();
- var destinationUrl = ioHelper.ResolveUrl(Url);
+ HttpContext httpContext = context.HttpContext;
+ IIOHelper ioHelper = httpContext.RequestServices.GetRequiredService();
+ string destinationUrl = ioHelper.ResolveUrl(Url);
if (_queryString.HasValue)
{
destinationUrl += _queryString.ToUriComponent();
}
- var tempDataDictionaryFactory = context.HttpContext.RequestServices.GetRequiredService();
- var tempData = tempDataDictionaryFactory.GetTempData(context.HttpContext);
- tempData?.Keep();
-
httpContext.Response.Redirect(destinationUrl);
return Task.CompletedTask;
diff --git a/src/Umbraco.Web.Website/ActionResults/UmbracoPageResult.cs b/src/Umbraco.Web.Website/ActionResults/UmbracoPageResult.cs
index 4eb40e8e4e..c2b3a1221b 100644
--- a/src/Umbraco.Web.Website/ActionResults/UmbracoPageResult.cs
+++ b/src/Umbraco.Web.Website/ActionResults/UmbracoPageResult.cs
@@ -1,21 +1,11 @@
using System;
-using System.Collections.Generic;
-using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
-using Microsoft.AspNetCore.Mvc.Controllers;
-using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
-using Microsoft.AspNetCore.Mvc.Rendering;
-using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
-using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
-using Umbraco.Core;
using Umbraco.Core.Logging;
-using Umbraco.Extensions;
-using Umbraco.Web.Common.Controllers;
using Umbraco.Web.Common.Routing;
using Umbraco.Web.Website.Controllers;
using Umbraco.Web.Website.Routing;
@@ -25,14 +15,19 @@ namespace Umbraco.Web.Website.ActionResults
///
/// Used by posted forms to proxy the result to the page in which the current URL matches on
///
+ ///
+ /// This page does not redirect therefore it does not implement because TempData should
+ /// only be used in situations when a redirect occurs. It is not good practice to use TempData when redirects do not occur
+ /// so we'll be strict about it and not save it.
+ ///
public class UmbracoPageResult : IActionResult
{
private readonly IProfilingLogger _profilingLogger;
- public UmbracoPageResult(IProfilingLogger profilingLogger)
- {
- _profilingLogger = profilingLogger;
- }
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UmbracoPageResult(IProfilingLogger profilingLogger) => _profilingLogger = profilingLogger;
///
public async Task ExecuteResultAsync(ActionContext context)
@@ -47,42 +42,15 @@ namespace Umbraco.Web.Website.ActionResults
context.RouteData.Values[UmbracoRouteValueTransformer.ControllerToken] = umbracoRouteValues.ControllerName;
context.RouteData.Values[UmbracoRouteValueTransformer.ActionToken] = umbracoRouteValues.ActionName;
- // Create a new context and excute the original controller
-
- // TODO: We need to take into account temp data, view data, etc... all like what we used to do below
- // so that validation stuff gets carried accross
-
- var renderActionContext = new ActionContext(context.HttpContext, context.RouteData, umbracoRouteValues.ControllerActionDescriptor);
+ // Create a new context and excute the original controller...
+ // Copy the action context - this also copies the ModelState
+ var renderActionContext = new ActionContext(context)
+ {
+ ActionDescriptor = umbracoRouteValues.ControllerActionDescriptor
+ };
IActionInvokerFactory actionInvokerFactory = context.HttpContext.RequestServices.GetRequiredService();
IActionInvoker actionInvoker = actionInvokerFactory.CreateInvoker(renderActionContext);
await ExecuteControllerAction(actionInvoker);
-
- //ResetRouteData(context.RouteData);
- //ValidateRouteData(context);
-
- //IControllerFactory factory = context.HttpContext.RequestServices.GetRequiredService();
- //Controller controller = null;
-
- //if (!(context is ControllerContext controllerContext))
- //{
- // // TODO: Better to throw since this is not expected?
- // return Task.FromCanceled(CancellationToken.None);
- //}
-
- //try
- //{
- // controller = CreateController(controllerContext, factory);
-
- // CopyControllerData(controllerContext, controller);
-
- // ExecuteControllerAction(controllerContext, controller);
- //}
- //finally
- //{
- // CleanupController(controllerContext, controller, factory);
- //}
-
- //return Task.CompletedTask;
}
///
@@ -95,83 +63,5 @@ namespace Umbraco.Web.Website.ActionResults
await actionInvoker.InvokeAsync();
}
}
-
- ///
- /// Creates action execution delegate from ActionExecutingContext
- ///
- private static ActionExecutionDelegate CreateActionExecutedDelegate(ActionExecutingContext context)
- {
- var actionExecutedContext = new ActionExecutedContext(context, context.Filters, context.Controller)
- {
- Result = context.Result,
- };
- return () => Task.FromResult(actionExecutedContext);
- }
-
- ///
- /// Ensure ModelState, ViewData and TempData is copied across
- ///
- private static void CopyControllerData(ControllerContext context, Controller controller)
- {
- controller.ViewData.ModelState.Merge(context.ModelState);
-
- foreach (KeyValuePair d in controller.ViewData)
- {
- controller.ViewData[d.Key] = d.Value;
- }
-
- // We cannot simply merge the temp data because during controller execution it will attempt to 'load' temp data
- // but since it has not been saved, there will be nothing to load and it will revert to nothing, so the trick is
- // to Save the state of the temp data first then it will automatically be picked up.
- // http://issues.umbraco.org/issue/U4-1339
-
- var targetController = controller;
- var tempDataDictionaryFactory = context.HttpContext.RequestServices.GetRequiredService();
- var tempData = tempDataDictionaryFactory.GetTempData(context.HttpContext);
-
- targetController.TempData = tempData;
- targetController.TempData.Save();
- }
-
- ///
- /// Creates a controller using the controller factory
- ///
- private static Controller CreateController(ControllerContext context, IControllerFactory factory)
- {
- if (!(factory.CreateController(context) is Controller controller))
- {
- throw new InvalidOperationException("Could not create controller with name " + context.ActionDescriptor.ControllerName + ".");
- }
-
- return controller;
- }
-
- ///
- /// Cleans up the controller by releasing it using the controller factory, and by disposing it.
- ///
- private static void CleanupController(ControllerContext context, Controller controller, IControllerFactory factory)
- {
- if (!(controller is null))
- {
- factory.ReleaseController(context, controller);
- }
-
- controller?.DisposeIfDisposable();
- }
-
- private class DummyView : IView
- {
- public DummyView(string path)
- {
- Path = path;
- }
-
- public Task RenderAsync(ViewContext context)
- {
- return Task.CompletedTask;
- }
-
- public string Path { get; }
- }
}
}
diff --git a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
index f7098e316d..4db3c605c9 100644
--- a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
+++ b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs
@@ -101,6 +101,9 @@ namespace Umbraco.Web.Website.Controllers
/// Returns the currently rendered Umbraco page
///
protected UmbracoPageResult CurrentUmbracoPage()
- => new UmbracoPageResult(ProfilingLogger);
+ {
+ HttpContext.Features.Set(new ProxyViewDataFeature(ViewData));
+ return new UmbracoPageResult(ProfilingLogger);
+ }
}
}