From 3e28376ae77651705b460666239f286c948314f0 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Sat, 19 Jan 2013 06:38:02 +0300 Subject: [PATCH] Fixes: #U4-1472 - XmlHelper. Fixes: #U4-1488 - partial view macro engine issues. --- src/Umbraco.Core/XmlHelper.cs | 14 +++---- .../Macros/PartialViewMacroEngine.cs | 41 +++++++++++-------- src/Umbraco.Web/Mvc/Constants.cs | 7 +++- src/Umbraco.Web/Mvc/ControllerExtensions.cs | 4 +- src/Umbraco.Web/Mvc/UmbracoViewPage.cs | 19 +++++++++ src/Umbraco.Web/Mvc/ViewContextExtensions.cs | 19 +++++++++ 6 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/Umbraco.Core/XmlHelper.cs b/src/Umbraco.Core/XmlHelper.cs index 0a3d16e9c8..27f4d0e923 100644 --- a/src/Umbraco.Core/XmlHelper.cs +++ b/src/Umbraco.Core/XmlHelper.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core /// The text. /// The XML doc. /// - internal static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc) + public static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc) { xmlDoc.LoadXml(text); return xmlDoc.FirstChild; @@ -80,7 +80,7 @@ namespace Umbraco.Core /// The node name. /// The node value. /// A XmlNode - public static XmlNode AddCDataNode(XmlDocument xd, string name, string value) + public static XmlNode AddCDataNode(XmlDocument xd, string name, string value) { var temp = xd.CreateNode(XmlNodeType.Element, name, ""); temp.AppendChild(xd.CreateCDataSection(value)); @@ -92,7 +92,7 @@ namespace Umbraco.Core /// /// The XmlNode. /// the value as a string - internal static string GetNodeValue(XmlNode n) + public static string GetNodeValue(XmlNode n) { var value = string.Empty; if (n == null || n.FirstChild == null) @@ -108,7 +108,7 @@ namespace Umbraco.Core /// /// true if the specified string appears to be XML; otherwise, false. /// - internal static bool CouldItBeXml(string xml) + public static bool CouldItBeXml(string xml) { if (!string.IsNullOrEmpty(xml)) { @@ -131,7 +131,7 @@ namespace Umbraco.Core /// Name of the root. /// Name of the element. /// Returns an System.Xml.XmlDocument representation of the delimited string data. - internal static XmlDocument Split(string data, string[] separator, string rootName, string elementName) + public static XmlDocument Split(string data, string[] separator, string rootName, string elementName) { return Split(new XmlDocument(), data, separator, rootName, elementName); } @@ -145,7 +145,7 @@ namespace Umbraco.Core /// Name of the root node. /// Name of the element node. /// Returns an System.Xml.XmlDocument representation of the delimited string data. - internal static XmlDocument Split(XmlDocument xml, string data, string[] separator, string rootName, string elementName) + public static XmlDocument Split(XmlDocument xml, string data, string[] separator, string rootName, string elementName) { // load new XML document. xml.LoadXml(string.Concat("<", rootName, "/>")); @@ -174,7 +174,7 @@ namespace Umbraco.Core /// /// /// - internal static Dictionary GetAttributesFromElement(string tag) + public static Dictionary GetAttributesFromElement(string tag) { var m = Regex.Matches(tag, "(?\\S*)=\"(?[^\"]*)\"", diff --git a/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs b/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs index 1d18aabad7..595c94bebb 100644 --- a/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs +++ b/src/Umbraco.Web/Macros/PartialViewMacroEngine.cs @@ -13,6 +13,7 @@ using umbraco.cms.businesslogic.macro; using umbraco.interfaces; using Umbraco.Web.Mvc; using Umbraco.Core; +using System.Web.Mvc.Html; namespace Umbraco.Web.Macros { @@ -65,8 +66,7 @@ namespace Umbraco.Web.Macros // we rewrite how macro engines work. public IEnumerable SupportedExtensions { - get { return Enumerable.Empty(); } - //get { return new[] {"cshtml", "vbhtml"}; } + get { return Enumerable.Empty(); } } //NOTE: We do not return any supported extensions because we don't want the MacroEngineFactory to return this @@ -76,7 +76,6 @@ namespace Umbraco.Web.Macros public IEnumerable SupportedUIExtensions { get { return Enumerable.Empty(); } - //get { return new[] { "cshtml", "vbhtml" }; } } public Dictionary SupportedProperties { @@ -118,26 +117,32 @@ namespace Umbraco.Web.Macros routeVals.Values.Add("action", "Index"); routeVals.DataTokens.Add("umbraco-context", umbCtx); //required for UmbracoViewPage - ////lets render this controller as a child action if we are currently executing using MVC - ////(otherwise don't do this since we're using webforms) - //var mvcHandler = http.CurrentHandler as MvcHandler; - //if (mvcHandler != null) - //{ - // routeVals.DataTokens.Add("ParentActionViewContext", - // //If we could get access to the currently executing controller we could do this but this is nearly - // //impossible. The only way to do that would be to store the controller instance in the route values - // //in the base class of the UmbracoController.... but not sure the reprocussions of that, i think it could - // //work but is a bit nasty. - // new ViewContext()); - //} + //lets render this controller as a child action if we are currently executing using MVC + //(otherwise don't do this since we're using webforms) + var mvcHandler = http.CurrentHandler as MvcHandler; + var viewContext = new ViewContext {ViewData = new ViewDataDictionary()};; + if (mvcHandler != null) + { + //try and extract the current view context from the route values, this would be set in the UmbracoViewPage. + if (mvcHandler.RequestContext.RouteData.DataTokens.ContainsKey(Constants.DataTokenCurrentViewContext)) + { + viewContext = (ViewContext) mvcHandler.RequestContext.RouteData.DataTokens[Constants.DataTokenCurrentViewContext]; + } + routeVals.DataTokens.Add("ParentActionViewContext", viewContext); + } var request = new RequestContext(http, routeVals); string output; using (var controller = new PartialViewMacroController(umbCtx, macro, currentPage)) { - controller.ControllerContext = new ControllerContext(request, controller); + //bubble up the model state from the main view context to our custom controller. + //when merging we'll create a new dictionary, otherwise you might run into an enumeration error + // caused from ModelStateDictionary + controller.ModelState.Merge(new ModelStateDictionary(viewContext.ViewData.ModelState)); + controller.ControllerContext = new ControllerContext(request, controller); + //call the action to render var result = controller.Index(); - output = controller.RenderViewResultAsString(result); + output = controller.RenderViewResultAsString(result); } return output; @@ -163,5 +168,7 @@ namespace Umbraco.Web.Macros throw new InvalidCastException("All Partial View Macro views must inherit from " + typeof(PartialViewMacroPage).FullName); return webPage; } + } + } diff --git a/src/Umbraco.Web/Mvc/Constants.cs b/src/Umbraco.Web/Mvc/Constants.cs index 1ec35e4928..4151c412f4 100644 --- a/src/Umbraco.Web/Mvc/Constants.cs +++ b/src/Umbraco.Web/Mvc/Constants.cs @@ -1,7 +1,12 @@ namespace Umbraco.Web.Mvc { + /// + /// constants + /// internal static class Constants { - public const string ViewLocation = "~/Views"; + internal const string ViewLocation = "~/Views"; + + internal const string DataTokenCurrentViewContext = "umbraco-current-view-context"; } } \ No newline at end of file diff --git a/src/Umbraco.Web/Mvc/ControllerExtensions.cs b/src/Umbraco.Web/Mvc/ControllerExtensions.cs index 59900e6489..b26ed39b79 100644 --- a/src/Umbraco.Web/Mvc/ControllerExtensions.cs +++ b/src/Umbraco.Web/Mvc/ControllerExtensions.cs @@ -108,7 +108,9 @@ namespace Umbraco.Web.Mvc /// internal static void EnsureViewObjectDataOnResult(this ControllerBase controller, ViewResultBase result) { - result.ViewData.ModelState.Merge(controller.ViewData.ModelState); + //when merging we'll create a new dictionary, otherwise you might run into an enumeration error + // caused from ModelStateDictionary + result.ViewData.ModelState.Merge(new ModelStateDictionary(controller.ViewData.ModelState)); // Temporarily copy the dictionary to avoid enumerator-modification errors var newViewDataDict = new ViewDataDictionary(controller.ViewData); diff --git a/src/Umbraco.Web/Mvc/UmbracoViewPage.cs b/src/Umbraco.Web/Mvc/UmbracoViewPage.cs index ff926fd4b4..92a46a9858 100644 --- a/src/Umbraco.Web/Mvc/UmbracoViewPage.cs +++ b/src/Umbraco.Web/Mvc/UmbracoViewPage.cs @@ -93,5 +93,24 @@ namespace Umbraco.Web.Mvc get { return _helper ?? (_helper = new UmbracoHelper(UmbracoContext)); } } + /// + /// Ensure that the current view context is added to the route data tokens so we can extract it if we like + /// + /// + /// Currently this is required by mvc macro engines + /// + protected override void InitializePage() + { + base.InitializePage(); + if (!ViewContext.IsChildAction) + { + if (!ViewContext.RouteData.DataTokens.ContainsKey(Constants.DataTokenCurrentViewContext)) + { + ViewContext.RouteData.DataTokens.Add(Constants.DataTokenCurrentViewContext, this.ViewContext); + } + } + + } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/Mvc/ViewContextExtensions.cs b/src/Umbraco.Web/Mvc/ViewContextExtensions.cs index 30dcccbbbb..1cb39e2487 100644 --- a/src/Umbraco.Web/Mvc/ViewContextExtensions.cs +++ b/src/Umbraco.Web/Mvc/ViewContextExtensions.cs @@ -1,3 +1,4 @@ +using System.IO; using System.Web.Mvc; namespace Umbraco.Web.Mvc @@ -30,5 +31,23 @@ namespace Umbraco.Web.Mvc Writer = vc.Writer }; } + + //public static ViewContext CloneWithWriter(this ViewContext vc, TextWriter writer) + //{ + // return new ViewContext + // { + // Controller = vc.Controller, + // HttpContext = vc.HttpContext, + // RequestContext = vc.RequestContext, + // RouteData = vc.RouteData, + // TempData = vc.TempData, + // View = vc.View, + // ViewData = vc.ViewData, + // FormContext = vc.FormContext, + // ClientValidationEnabled = vc.ClientValidationEnabled, + // UnobtrusiveJavaScriptEnabled = vc.UnobtrusiveJavaScriptEnabled, + // Writer = writer + // }; + //} } } \ No newline at end of file