diff --git a/src/Umbraco.Web/Mvc/RouteDefinition.cs b/src/Umbraco.Web/Mvc/RouteDefinition.cs
index 49ba64fac5..f0334202dd 100644
--- a/src/Umbraco.Web/Mvc/RouteDefinition.cs
+++ b/src/Umbraco.Web/Mvc/RouteDefinition.cs
@@ -11,12 +11,7 @@ namespace Umbraco.Web.Mvc
{
public string ControllerName { get; set; }
public string ActionName { get; set; }
-
- ///
- /// The Controller instance found for routing to
- ///
- public ControllerBase Controller { get; set; }
-
+
///
/// The Controller type found for routing to
///
diff --git a/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs b/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs
index 649ac54f27..6e7a92ea10 100644
--- a/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs
+++ b/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs
@@ -1,23 +1,18 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Web;
-using System.Web.Mvc;
+using System.Web.Mvc;
using System.Web.Routing;
namespace Umbraco.Web.Mvc
{
///
- /// Mvc handler class to intercept creation of controller and store it for later use.
- /// This means we create two instances of the same controller to support some features later on.
+ /// MVC handler to facilitate the TemplateRenderer. This handler can execute an MVC request and return it as a string.
///
- /// The alternate option for this is to completely rewrite all MvcHandler methods.
+ /// Original:
///
- /// This is currently needed for the 'return CurrentUmbracoPage()' surface controller functionality
+ /// This handler also used to intercept creation of controllers and store it for later use.
+ /// This was needed for the 'return CurrentUmbracoPage()' surface controller functionality
/// because it needs to send data back to the page controller.
+ ///
+ /// The creation of this controller has been moved to the UmbracoPageResult class which will create a controller when needed.
///
internal class UmbracoMvcHandler : MvcHandler
{
@@ -25,46 +20,13 @@ namespace Umbraco.Web.Mvc
: base(requestContext)
{
}
-
- private void StoreControllerInRouteDefinition()
- {
- var routeDef = (RouteDefinition)RequestContext.RouteData.DataTokens["umbraco-route-def"];
-
- if (routeDef == null) return;
-
- // 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 is used internally purely to render an Umbraco MVC template to string and shouldn't be used for anything else.
///
internal void ExecuteUmbracoRequest()
{
- StoreControllerInRouteDefinition();
base.ProcessRequest(RequestContext.HttpContext);
}
-
- protected override void ProcessRequest(HttpContextBase httpContext)
- {
- StoreControllerInRouteDefinition();
-
- // Let MVC do its magic and continue the request
- base.ProcessRequest(httpContext);
- }
-
- protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback,
- object state)
- {
- StoreControllerInRouteDefinition();
-
- return base.BeginProcessRequest(httpContext, callback, state);
- }
}
-
-
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Mvc/UmbracoPageResult.cs b/src/Umbraco.Web/Mvc/UmbracoPageResult.cs
index 9ae5006d48..6b44959c8c 100644
--- a/src/Umbraco.Web/Mvc/UmbracoPageResult.cs
+++ b/src/Umbraco.Web/Mvc/UmbracoPageResult.cs
@@ -1,5 +1,6 @@
using System;
using System.Web.Mvc;
+using System.Web.Routing;
using Umbraco.Core;
namespace Umbraco.Web.Mvc
@@ -11,54 +12,100 @@ namespace Umbraco.Web.Mvc
{
public override void ExecuteResult(ControllerContext context)
{
+ ResetRouteData(context.RouteData);
- //since we could be returning the current page from a surface controller posted values in which the routing values are changed, we
- //need to revert these values back to nothing in order for the normal page to render again.
- context.RouteData.DataTokens["area"] = null;
- context.RouteData.DataTokens["Namespaces"] = null;
-
- //validate that the current page execution is not being handled by the normal umbraco routing system
- if (!context.RouteData.DataTokens.ContainsKey("umbraco-route-def"))
- {
- throw new InvalidOperationException("Can only use " + typeof(UmbracoPageResult).Name + " in the context of an Http POST when using a SurfaceController form");
- }
+ ValidateRouteData(context.RouteData);
var routeDef = (RouteDefinition)context.RouteData.DataTokens["umbraco-route-def"];
+ var factory = ControllerBuilder.Current.GetControllerFactory();
- var targetController = ((Controller)routeDef.Controller);
- var sourceController = ((Controller) context.Controller);
-
- //ensure the original template is reset
context.RouteData.Values["action"] = routeDef.ActionName;
- //ensure ModelState is copied across
- routeDef.Controller.ViewData.ModelState.Merge(sourceController.ViewData.ModelState);
+ ControllerBase controller = null;
- //ensure TempData and ViewData is copied across
- foreach (var d in sourceController.ViewData)
- routeDef.Controller.ViewData[d.Key] = d.Value;
+ try
+ {
+ controller = CreateController(context, factory, routeDef);
+
+ controller.ViewData.ModelState.Merge(context.Controller.ViewData.ModelState);
+ CopyControllerData(context, controller);
- //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
- targetController.TempDataProvider = sourceController.TempDataProvider;
- targetController.TempData = sourceController.TempData;
- targetController.TempData.Save(sourceController.ControllerContext, sourceController.TempDataProvider);
-
- using (DisposableTimer.TraceDuration("Executing Umbraco RouteDefinition controller", "Finished"))
- {
- try
- {
- ((IController)targetController).Execute(context.RequestContext);
- }
- finally
- {
- routeDef.Controller.DisposeIfDisposable();
- }
- }
-
+ ExecuteControllerAction(context, controller);
+ }
+ finally
+ {
+ CleanupController(controller, factory);
+ }
}
+
+ ///
+ /// Executes the controller action
+ ///
+ private static void ExecuteControllerAction(ControllerContext context, IController controller)
+ {
+ using (DisposableTimer.TraceDuration("Executing Umbraco RouteDefinition controller", "Finished"))
+ {
+ controller.Execute(context.RequestContext);
+ }
+ }
+
+ ///
+ /// Since we could be returning the current page from a surface controller posted values in which the routing values are changed, we
+ /// need to revert these values back to nothing in order for the normal page to render again.
+ ///
+ private static void ResetRouteData(RouteData routeData)
+ {
+ routeData.DataTokens["area"] = null;
+ routeData.DataTokens["Namespaces"] = null;
+ }
+
+ ///
+ /// Validate that the current page execution is not being handled by the normal umbraco routing system
+ ///
+ private static void ValidateRouteData(RouteData routeData)
+ {
+ if (!routeData.DataTokens.ContainsKey("umbraco-route-def"))
+ {
+ throw new InvalidOperationException("Can only use " + typeof(UmbracoPageResult).Name +
+ " in the context of an Http POST when using a SurfaceController form");
+ }
+ }
+
+ ///
+ /// Ensure TempData and ViewData is copied across
+ ///
+ private static void CopyControllerData(ControllerContext context, ControllerBase controller)
+ {
+ foreach (var d in context.Controller.ViewData)
+ controller.ViewData[d.Key] = d.Value;
+
+ controller.TempData = context.Controller.TempData;
+ }
+
+ ///
+ /// Creates a controller using the controller factory
+ ///
+ private static ControllerBase CreateController(ControllerContext context, IControllerFactory factory, RouteDefinition routeDef)
+ {
+ var controller = factory.CreateController(context.RequestContext, routeDef.ControllerName) as ControllerBase;
+
+ if (controller == null)
+ throw new InvalidOperationException("Could not create controller with name " + routeDef.ControllerName + ".");
+
+ return controller;
+ }
+
+ ///
+ /// Cleans up the controller by releasing it using the controller factory, and by disposing it.
+ ///
+ private static void CleanupController(IController controller, IControllerFactory factory)
+ {
+ if (controller != null)
+ factory.ReleaseController(controller);
+
+ if (controller != null)
+ controller.DisposeIfDisposable();
+ }
}
}
\ No newline at end of file