Fixes #U4-1174 - allows MVC views to render when using RenderTemplate. Added new UmbracoHelper method RenderTemplate. Cleaned up some code and
ensuring that the string writers are disposed. Moved TemplateRenderer to a better namespace.
This commit is contained in:
@@ -69,23 +69,28 @@ namespace Umbraco.Web.Mvc
|
||||
return sw.ToString().Trim();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Renders the partial view to string.
|
||||
/// </summary>
|
||||
/// <param name="controller">The controller context.</param>
|
||||
/// <param name="viewName">Name of the view.</param>
|
||||
/// <param name="model">The model.</param>
|
||||
/// <param name="isPartial">true if it is a Partial view, otherwise false for a normal view </param>
|
||||
/// <returns></returns>
|
||||
internal static string RenderPartialViewToString(this ControllerBase controller, string viewName, object model)
|
||||
internal static string RenderViewToString(this ControllerBase controller, string viewName, object model, bool isPartial = false)
|
||||
{
|
||||
if (controller.ControllerContext == null)
|
||||
throw new ArgumentException("The controller must have an assigned ControllerContext to execute this method.");
|
||||
|
||||
controller.ViewData.Model = model;
|
||||
|
||||
using (StringWriter sw = new StringWriter())
|
||||
using (var sw = new StringWriter())
|
||||
{
|
||||
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
|
||||
ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
|
||||
var viewResult = !isPartial
|
||||
? ViewEngines.Engines.FindView(controller.ControllerContext, viewName, null)
|
||||
: ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
|
||||
var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
|
||||
viewResult.View.Render(viewContext, sw);
|
||||
|
||||
return sw.GetStringBuilder().ToString();
|
||||
|
||||
@@ -65,13 +65,11 @@ namespace Umbraco.Web.Mvc
|
||||
{
|
||||
throw new NullReferenceException("There is not current PublishedContentRequest, it must be initialized before the RenderRouteHandler executes");
|
||||
}
|
||||
|
||||
var renderModel = new RenderModel(docRequest.PublishedContent, docRequest.Culture);
|
||||
|
||||
//put essential data into the data tokens, the 'umbraco' key is required to be there for the view engine
|
||||
requestContext.RouteData.DataTokens.Add("umbraco", renderModel); //required for the RenderModelBinder
|
||||
requestContext.RouteData.DataTokens.Add("umbraco-doc-request", docRequest); //required for RenderMvcController
|
||||
requestContext.RouteData.DataTokens.Add("umbraco-context", UmbracoContext); //required for UmbracoTemplatePage
|
||||
|
||||
SetupRouteDataForRequest(
|
||||
new RenderModel(docRequest.PublishedContent, docRequest.Culture),
|
||||
requestContext,
|
||||
docRequest);
|
||||
|
||||
return GetHandlerForRoute(requestContext, docRequest);
|
||||
|
||||
@@ -79,6 +77,20 @@ namespace Umbraco.Web.Mvc
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that all of the correct DataTokens are added to the route values which are all required for rendering front-end umbraco views
|
||||
/// </summary>
|
||||
/// <param name="renderModel"></param>
|
||||
/// <param name="requestContext"></param>
|
||||
/// <param name="docRequest"></param>
|
||||
internal void SetupRouteDataForRequest(RenderModel renderModel, RequestContext requestContext, PublishedContentRequest docRequest)
|
||||
{
|
||||
//put essential data into the data tokens, the 'umbraco' key is required to be there for the view engine
|
||||
requestContext.RouteData.DataTokens.Add("umbraco", renderModel); //required for the RenderModelBinder and view engine
|
||||
requestContext.RouteData.DataTokens.Add("umbraco-doc-request", docRequest); //required for RenderMvcController
|
||||
requestContext.RouteData.DataTokens.Add("umbraco-context", UmbracoContext); //required for UmbracoTemplatePage
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the request and query strings to see if it matches the definition of having a Surface controller
|
||||
/// posted value, if so, then we return a PostedDataProxyInfo object with the correct information.
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Web.Compilation;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Routing;
|
||||
using umbraco;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Web.Routing
|
||||
namespace Umbraco.Web.Templates
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used purely for the RenderTemplate functionality in Umbraco
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently the only place where you can use RenderTemplate is from within the library class (which is legacy)
|
||||
/// but i guess we still need to support it. In order to do that we need to be able to render both an MVC and Webforms
|
||||
/// template. So we will do a Server.Execute to execute this handler, this will then need to find put the 'id' request through
|
||||
/// the routing logic again, the execute the correct handler.
|
||||
/// Its is pretty round about but is required.
|
||||
/// This allows you to render either an MVC or Webforms template based purely off of a node id and an optional alttemplate id as string output.
|
||||
/// </remarks>
|
||||
internal class TemplateRenderer
|
||||
{
|
||||
@@ -27,21 +25,23 @@ namespace Umbraco.Web.Routing
|
||||
private PublishedContentRequest _oldPublishedContentRequest;
|
||||
private object _oldAltTemplate;
|
||||
|
||||
public TemplateRenderer(UmbracoContext umbracoContext)
|
||||
public TemplateRenderer(UmbracoContext umbracoContext, int pageId, int? altTemplateId)
|
||||
{
|
||||
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
|
||||
PageId = pageId;
|
||||
AltTemplate = altTemplateId;
|
||||
_umbracoContext = umbracoContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the page id for the template to render
|
||||
/// </summary>
|
||||
public int PageId { get; set; }
|
||||
public int PageId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the alt template to render if there is one
|
||||
/// </summary>
|
||||
public int? AltTemplate { get; set; }
|
||||
public int? AltTemplate { get; private set; }
|
||||
|
||||
public void Render(StringWriter writer)
|
||||
{
|
||||
@@ -103,7 +103,7 @@ namespace Umbraco.Web.Routing
|
||||
RestoreItems();
|
||||
}
|
||||
|
||||
private void ExecuteTemplateRendering(StringWriter sw, PublishedContentRequest contentRequest)
|
||||
private void ExecuteTemplateRendering(TextWriter sw, PublishedContentRequest contentRequest)
|
||||
{
|
||||
//NOTE: Before we used to build up the query strings here but this is not necessary because when we do a
|
||||
// Server.Execute in the TemplateRenderer, we pass in a 'true' to 'preserveForm' which automatically preserves all current
|
||||
@@ -112,11 +112,29 @@ namespace Umbraco.Web.Routing
|
||||
|
||||
//var queryString = _umbracoContext.HttpContext.Request.QueryString.AllKeys
|
||||
// .ToDictionary(key => key, key => context.Request.QueryString[key]);
|
||||
|
||||
|
||||
switch (contentRequest.RenderingEngine)
|
||||
{
|
||||
case RenderingEngine.Mvc:
|
||||
throw new NotImplementedException("Currently the TemplateRender does not support rendering MVC templates");
|
||||
var requestContext = new RequestContext(_umbracoContext.HttpContext, new RouteData()
|
||||
{
|
||||
Route = RouteTable.Routes["Umbraco_default"]
|
||||
});
|
||||
var routeHandler = new RenderRouteHandler(ControllerBuilder.Current.GetControllerFactory(), _umbracoContext);
|
||||
var routeDef = routeHandler.GetUmbracoRouteDefinition(requestContext, contentRequest);
|
||||
var renderModel = new RenderModel(contentRequest.PublishedContent, contentRequest.Culture);
|
||||
//manually add the action/controller, this is required by mvc
|
||||
requestContext.RouteData.Values.Add("action", routeDef.ActionName);
|
||||
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);
|
||||
sw.Write(stringOutput);
|
||||
break;
|
||||
case RenderingEngine.WebForms:
|
||||
default:
|
||||
@@ -126,7 +144,8 @@ namespace Umbraco.Web.Routing
|
||||
// to build up the url again, it will just work.
|
||||
_umbracoContext.HttpContext.Server.Execute(webFormshandler, sw, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void SetNewItemsOnContextObjects(PublishedContentRequest contentRequest)
|
||||
@@ -312,7 +312,7 @@
|
||||
<Compile Include="RouteCollectionExtensions.cs" />
|
||||
<Compile Include="Routing\LookupByPageIdQuery.cs" />
|
||||
<Compile Include="Mvc\SurfaceControllerResolver.cs" />
|
||||
<Compile Include="Routing\TemplateRenderer.cs" />
|
||||
<Compile Include="Templates\TemplateRenderer.cs" />
|
||||
<Compile Include="Templates\TemplateUtilities.cs" />
|
||||
<Compile Include="umbraco.presentation\Default.aspx.cs">
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
|
||||
@@ -17,6 +17,7 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Templates;
|
||||
using umbraco;
|
||||
using System.Collections.Generic;
|
||||
@@ -63,6 +64,28 @@ namespace Umbraco.Web
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the template for the specified pageId and an optional altTemplateId
|
||||
/// </summary>
|
||||
/// <param name="pageId"></param>
|
||||
/// <param name="altTemplateId">If not specified, will use the template assigned to the node</param>
|
||||
/// <returns></returns>
|
||||
public IHtmlString RenderTemplate(int pageId, int? altTemplateId = null)
|
||||
{
|
||||
var templateRenderer = new TemplateRenderer(_umbracoContext, pageId, altTemplateId);
|
||||
using (var sw = new StringWriter())
|
||||
{
|
||||
try
|
||||
{
|
||||
templateRenderer.Render(sw);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
sw.Write("<!-- Error rendering template with id {0}: '{1}' -->", pageId, ex);
|
||||
}
|
||||
return new HtmlString(sw.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
#region RenderMacro
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using System.Xml.XPath;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Templates;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.cms.businesslogic;
|
||||
using umbraco.cms.businesslogic.media;
|
||||
@@ -1105,25 +1106,21 @@ namespace umbraco
|
||||
{
|
||||
if (!UmbracoContext.Current.LiveEditingContext.Enabled)
|
||||
{
|
||||
var sw = new StringWriter();
|
||||
|
||||
try
|
||||
{
|
||||
var altTemplate = TemplateId == -1 ? null : (int?)TemplateId;
|
||||
var templateRenderer = new TemplateRenderer(Umbraco.Web.UmbracoContext.Current)
|
||||
using (var sw = new StringWriter())
|
||||
{
|
||||
try
|
||||
{
|
||||
PageId = PageId,
|
||||
AltTemplate = altTemplate
|
||||
};
|
||||
templateRenderer.Render(sw);
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
sw.Write("<!-- Error generating macroContent: '{0}' -->", ee);
|
||||
}
|
||||
|
||||
return sw.ToString();
|
||||
var altTemplate = TemplateId == -1 ? null : (int?)TemplateId;
|
||||
var templateRenderer = new TemplateRenderer(Umbraco.Web.UmbracoContext.Current, PageId, altTemplate);
|
||||
templateRenderer.Render(sw);
|
||||
}
|
||||
catch (Exception ee)
|
||||
{
|
||||
sw.Write("<!-- Error rendering template with id {0}: '{1}' -->", PageId, ee);
|
||||
}
|
||||
|
||||
return sw.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1136,10 +1133,14 @@ namespace umbraco
|
||||
var p = new page(((IHasXmlNode)GetXmlNodeById(PageId.ToString()).Current).GetNode());
|
||||
p.RenderPage(TemplateId);
|
||||
var c = p.PageContentControl;
|
||||
var sw = new StringWriter();
|
||||
var hw = new HtmlTextWriter(sw);
|
||||
c.RenderControl(hw);
|
||||
return sw.ToString();
|
||||
|
||||
using (var sw = new StringWriter())
|
||||
using(var hw = new HtmlTextWriter(sw))
|
||||
{
|
||||
c.RenderControl(hw);
|
||||
return sw.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user