From 048480d5be9ff1fa6b6681608b5453169e8ab7ba Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 5 Jul 2013 14:12:31 +1000 Subject: [PATCH] Fixes: #U4-2460 - UmbracoHelper.RenderTemplate will now execute the complete MVC cycle when rendering MVC templates whereas before it would only execute the view which means any actionfilters, etc... applied would never have fired (as well as other things) --- src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs | 13 +++++ .../Standalone/StandaloneHttpContext.cs | 52 ++++++++++++++++++- src/Umbraco.Web/Templates/TemplateRenderer.cs | 36 ++++++++++--- 3 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs b/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs index 1ace297bfd..649ac54f27 100644 --- a/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs +++ b/src/Umbraco.Web/Mvc/UmbracoMvcHandler.cs @@ -1,5 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Web; @@ -38,6 +40,15 @@ namespace Umbraco.Web.Mvc 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(); @@ -54,4 +65,6 @@ namespace Umbraco.Web.Mvc return base.BeginProcessRequest(httpContext, callback, state); } } + + } \ No newline at end of file diff --git a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs index 4cf64a8adf..55339e97b6 100644 --- a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs +++ b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs @@ -1,5 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Web; @@ -11,11 +13,59 @@ namespace Umbraco.Web.Standalone /// internal class StandaloneHttpContext : HttpContextBase { + private readonly string _url; + private readonly HttpSessionStateBase _session = new StandaloneHttpSessionState(); + private readonly HttpResponseBase _response; + private readonly HttpRequestBase _request = new StandaloneHttpRequest(); + private readonly TextWriter _writer = new StringWriter(); + private readonly IDictionary _items = new Dictionary(); + + public StandaloneHttpContext() + { + //create a custom response with a custom writer. + _response = new HttpResponseWrapper(new HttpResponse(_writer)); + } + + public StandaloneHttpContext(string url) + : this() + { + if (url == null) throw new ArgumentNullException("url"); + _url = url; + _request = new HttpRequestWrapper(new HttpRequest("", _url, "")); + } + + // fixme - what shall we implement here? + + public override IDictionary Items + { + get { return _items; } + } + + public override HttpSessionStateBase Session + { + get { return _session; } + } public override HttpRequestBase Request { - get { return null; } + get { return _request; } } + + public override HttpResponseBase Response + { + get { return _response; } + } + + } + + internal class StandaloneHttpSessionState : HttpSessionStateBase + { + + } + + internal class StandaloneHttpRequest : HttpRequestBase + { + } } diff --git a/src/Umbraco.Web/Templates/TemplateRenderer.cs b/src/Umbraco.Web/Templates/TemplateRenderer.cs index fe60c6959e..a13ed031f8 100644 --- a/src/Umbraco.Web/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web/Templates/TemplateRenderer.cs @@ -137,12 +137,9 @@ namespace Umbraco.Web.Templates requestContext.RouteData.Values.Add("controller", routeDef.ControllerName); //add the rest of the required route data routeHandler.SetupRouteDataForRequest(renderModel, requestContext, contentRequest); - //create and assign the controller context - routeDef.Controller.ControllerContext = new ControllerContext(requestContext, routeDef.Controller); - //render as string - var stringOutput = routeDef.Controller.RenderViewToString( - routeDef.ActionName, - renderModel); + + var stringOutput = RenderUmbracoRequestToString(requestContext); + sw.Write(stringOutput); break; case RenderingEngine.WebForms: @@ -157,6 +154,33 @@ namespace Umbraco.Web.Templates } + /// + /// This will execute the UmbracoMvcHandler for the request specified and get the string output. + /// + /// + /// Assumes the RequestContext is setup specifically to render an Umbraco view. + /// + /// + /// + /// To acheive this we temporarily change the output text writer of the current HttpResponse, then + /// execute the controller via the handler which innevitably writes the result to the text writer + /// that has been assigned to the response. Then we change the response textwriter back to the original + /// before continuing . + /// + private string RenderUmbracoRequestToString(RequestContext requestContext) + { + var currentWriter = requestContext.HttpContext.Response.Output; + var newWriter = new StringWriter(); + requestContext.HttpContext.Response.Output = newWriter; + + var handler = new UmbracoMvcHandler(requestContext); + handler.ExecuteUmbracoRequest(); + + //reset it + requestContext.HttpContext.Response.Output = currentWriter; + return newWriter.ToString(); + } + private void SetNewItemsOnContextObjects(PublishedContentRequest contentRequest) { // handlers like default.aspx will want it and most macros currently need it