From 980cd20e4cfb9add76d612e8c77db7efb462fb90 Mon Sep 17 00:00:00 2001 From: "NielsHartvig@UMBRACORATI.localdomain" Date: Fri, 10 May 2013 10:24:25 -0200 Subject: [PATCH] Adjustments to profiling --- src/Umbraco.Core/UmbracoApplicationBase.cs | 4 +- .../umbraco.presentation/default.aspx.cs | 317 ++++++------ .../umbraco.presentation/helper.cs | 3 + src/Umbraco.Web/umbraco.presentation/item.cs | 326 ++++++------ .../umbraco/templateControls/ItemRenderer.cs | 465 +++++++++--------- 5 files changed, 573 insertions(+), 542 deletions(-) diff --git a/src/Umbraco.Core/UmbracoApplicationBase.cs b/src/Umbraco.Core/UmbracoApplicationBase.cs index cd6a611b0b..49bf3337a1 100644 --- a/src/Umbraco.Core/UmbracoApplicationBase.cs +++ b/src/Umbraco.Core/UmbracoApplicationBase.cs @@ -54,7 +54,7 @@ namespace Umbraco.Core { if (GlobalSettings.DebugMode) { - if (!String.IsNullOrEmpty(Request["umbDebug"]) || Request.Path.Contains(Umbraco.Core.IO.SystemDirectories.Umbraco) ) + if (!String.IsNullOrEmpty(Request["umbDebug"])) Umbraco.Core.Profiling.Profiler.Instance.Start(); } } @@ -63,7 +63,7 @@ namespace Umbraco.Core { if (GlobalSettings.DebugMode) { - if (!String.IsNullOrEmpty(Request["umbDebug"]) || Request.Path.Contains(Umbraco.Core.IO.SystemDirectories.Umbraco)) + if (!String.IsNullOrEmpty(Request["umbDebug"])) Umbraco.Core.Profiling.Profiler.Instance.Stop(); } } diff --git a/src/Umbraco.Web/umbraco.presentation/default.aspx.cs b/src/Umbraco.Web/umbraco.presentation/default.aspx.cs index c8c04813c5..14345b721d 100644 --- a/src/Umbraco.Web/umbraco.presentation/default.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/default.aspx.cs @@ -18,183 +18,196 @@ using umbraco.cms.businesslogic; namespace umbraco { - /// - /// The codebehind class for the main default.aspx page that does the webforms rendering in Umbraco - /// - /// - /// We would move this to the UI project but there is a public API property and some protected properties which people may be using so - /// we cannot move it. - /// - public class UmbracoDefault : Page - { - private page _upage; - private PublishedContentRequest _docRequest; - bool _validateRequest = true; + /// + /// The codebehind class for the main default.aspx page that does the webforms rendering in Umbraco + /// + /// + /// We would move this to the UI project but there is a public API property and some protected properties which people may be using so + /// we cannot move it. + /// + public class UmbracoDefault : Page + { + private page _upage; + private PublishedContentRequest _docRequest; + bool _validateRequest = true; - /// - /// To turn off request validation set this to false before the PageLoad event. This equivalent to the validateRequest page directive - /// and has nothing to do with "normal" validation controls. Default value is true. - /// - public bool ValidateRequest - { - get { return _validateRequest; } - set { _validateRequest = value; } - } + /// + /// To turn off request validation set this to false before the PageLoad event. This equivalent to the validateRequest page directive + /// and has nothing to do with "normal" validation controls. Default value is true. + /// + public bool ValidateRequest + { + get { return _validateRequest; } + set { _validateRequest = value; } + } - protected override void OnPreInit(EventArgs e) - { - base.OnPreInit(e); + protected override void OnPreInit(EventArgs e) + { + base.OnPreInit(e); + using (Umbraco.Core.Profiling.Profiler.Instance.Step("PreInit")) + { - // handle the infamous umbDebugShowTrace, etc - Page.Trace.IsEnabled &= GlobalSettings.DebugMode && !String.IsNullOrWhiteSpace(Request["umbDebugShowTrace"]); + // handle the infamous umbDebugShowTrace, etc + Page.Trace.IsEnabled &= GlobalSettings.DebugMode && !String.IsNullOrWhiteSpace(Request["umbDebugShowTrace"]); - // get the document request and the page - _docRequest = UmbracoContext.Current.PublishedContentRequest; - _upage = _docRequest.UmbracoPage; + // get the document request and the page + _docRequest = UmbracoContext.Current.PublishedContentRequest; + _upage = _docRequest.UmbracoPage; - //we need to check this for backwards compatibility in case people still arent' using master pages - if (UmbracoSettings.UseAspNetMasterPages) - { - var args = new RequestInitEventArgs() - { - Page = _upage, - PageId = _upage.PageID, - Context = Context - }; - FireBeforeRequestInit(args); + //we need to check this for backwards compatibility in case people still arent' using master pages + if (UmbracoSettings.UseAspNetMasterPages) + { + var args = new RequestInitEventArgs() + { + Page = _upage, + PageId = _upage.PageID, + Context = Context + }; + FireBeforeRequestInit(args); - //if we are cancelling then return and don't proceed - if (args.Cancel) return; + //if we are cancelling then return and don't proceed + if (args.Cancel) return; - this.MasterPageFile = template.GetMasterPageName(_upage.Template); + this.MasterPageFile = template.GetMasterPageName(_upage.Template); - // reset the friendly path so it's used by forms, etc. - Context.RewritePath(UmbracoContext.Current.OriginalRequestUrl.PathAndQuery); + // reset the friendly path so it's used by forms, etc. + Context.RewritePath(UmbracoContext.Current.OriginalRequestUrl.PathAndQuery); - //fire the init finished event - FireAfterRequestInit(args); - } - - } + //fire the init finished event + FireAfterRequestInit(args); + } + } + } - protected override void OnInit(EventArgs e) - { - base.OnInit(e); + protected override void OnInit(EventArgs e) + { + using (Umbraco.Core.Profiling.Profiler.Instance.Step("Init")) + { - //This is only here for legacy if people arent' using master pages... - //TODO: We need to test that this still works!! Or do we ?? - if (!UmbracoSettings.UseAspNetMasterPages) - { - var args = new RequestInitEventArgs() - { - Page = _upage, - PageId = _upage.PageID, - Context = Context - }; - FireBeforeRequestInit(args); + base.OnInit(e); - //if we are cancelling then return and don't proceed - if (args.Cancel) return; + //This is only here for legacy if people arent' using master pages... + //TODO: We need to test that this still works!! Or do we ?? + if (!UmbracoSettings.UseAspNetMasterPages) + { + var args = new RequestInitEventArgs() + { + Page = _upage, + PageId = _upage.PageID, + Context = Context + }; + FireBeforeRequestInit(args); - var pageHolder = new umbraco.layoutControls.umbracoPageHolder - { - ID = "umbPageHolder" - }; - Page.Controls.Add(pageHolder); - _upage.RenderPage(_upage.Template); - var umbPageHolder = (layoutControls.umbracoPageHolder)Page.FindControl("umbPageHolder"); - umbPageHolder.Populate(_upage); + //if we are cancelling then return and don't proceed + if (args.Cancel) return; - //fire the init finished event - FireAfterRequestInit(args); - } - } + var pageHolder = new umbraco.layoutControls.umbracoPageHolder + { + ID = "umbPageHolder" + }; + Page.Controls.Add(pageHolder); + _upage.RenderPage(_upage.Template); + var umbPageHolder = (layoutControls.umbracoPageHolder)Page.FindControl("umbPageHolder"); + umbPageHolder.Populate(_upage); - protected override void OnLoad(EventArgs e) - { - base.OnLoad(e); + //fire the init finished event + FireAfterRequestInit(args); + } + } + } - // do not validate when liveEditing because there may be a RTE with markup - var liveEditing = umbraco.presentation.UmbracoContext.Current.LiveEditingContext.Enabled; + protected override void OnLoad(EventArgs e) + { + using (Umbraco.Core.Profiling.Profiler.Instance.Step("Load")) + { + base.OnLoad(e); - if (!liveEditing && ValidateRequest) - Request.ValidateInput(); - } + // do not validate when liveEditing because there may be a RTE with markup + var liveEditing = umbraco.presentation.UmbracoContext.Current.LiveEditingContext.Enabled; - protected override void Render(HtmlTextWriter writer) - { - // do the original rendering - TextWriter sw = new StringWriter(); - base.Render(new HtmlTextWriter(sw)); - string text = sw.ToString(); + if (!liveEditing && ValidateRequest) + Request.ValidateInput(); + } + } - // filter / parse internal links - although this should be done elsewhere! - text = TemplateUtilities.ParseInternalLinks(text); + protected override void Render(HtmlTextWriter writer) + { + using (Umbraco.Core.Profiling.Profiler.Instance.Step("Render")) + { - // filter / add preview banner - if (UmbracoContext.Current.InPreviewMode) - { - LogHelper.Debug("Umbraco is running in preview mode.", true); + // do the original rendering + TextWriter sw = new StringWriter(); + base.Render(new HtmlTextWriter(sw)); + string text = sw.ToString(); - if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value - { - int pos = text.ToLower().IndexOf(""); - if (pos > -1) - { - string htmlBadge = - String.Format(UmbracoSettings.PreviewBadge, - IOHelper.ResolveUrl(SystemDirectories.Umbraco), - IOHelper.ResolveUrl(SystemDirectories.UmbracoClient), - Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path)); + // filter / parse internal links - although this should be done elsewhere! + text = TemplateUtilities.ParseInternalLinks(text); - text = text.Substring(0, pos) + htmlBadge + text.Substring(pos, text.Length - pos); - } - } - } + // filter / add preview banner + if (UmbracoContext.Current.InPreviewMode) + { + LogHelper.Debug("Umbraco is running in preview mode.", true); - // render - writer.Write(text); - } + if (Response.ContentType.InvariantEquals("text/html")) // ASP.NET default value + { + int pos = text.ToLower().IndexOf(""); + if (pos > -1) + { + string htmlBadge = + String.Format(UmbracoSettings.PreviewBadge, + IOHelper.ResolveUrl(SystemDirectories.Umbraco), + IOHelper.ResolveUrl(SystemDirectories.UmbracoClient), + Server.UrlEncode(UmbracoContext.Current.HttpContext.Request.Path)); - /// - /// The preinit event handler - /// - public delegate void RequestInitEventHandler(object sender, RequestInitEventArgs e); - /// - /// occurs before the umbraco page is initialized for rendering. - /// - public static event RequestInitEventHandler BeforeRequestInit; - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected internal virtual void FireBeforeRequestInit(RequestInitEventArgs e) - { - if (BeforeRequestInit != null) - BeforeRequestInit(this, e); - } + text = text.Substring(0, pos) + htmlBadge + text.Substring(pos, text.Length - pos); + } + } + } - /// - /// Occurs when [after save]. - /// - public static event RequestInitEventHandler AfterRequestInit; - /// - /// Raises the event. - /// - /// The instance containing the event data. - protected virtual void FireAfterRequestInit(RequestInitEventArgs e) - { - if (AfterRequestInit != null) - AfterRequestInit(this, e); + // render + writer.Write(text); + } + } - } - } + /// + /// The preinit event handler + /// + public delegate void RequestInitEventHandler(object sender, RequestInitEventArgs e); + /// + /// occurs before the umbraco page is initialized for rendering. + /// + public static event RequestInitEventHandler BeforeRequestInit; + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected internal virtual void FireBeforeRequestInit(RequestInitEventArgs e) + { + if (BeforeRequestInit != null) + BeforeRequestInit(this, e); + } - public class RequestInitEventArgs : System.ComponentModel.CancelEventArgs - { - public page Page { get; internal set; } - public HttpContext Context { get; internal set; } - public string Url { get; internal set; } - public int PageId { get; internal set; } - } + /// + /// Occurs when [after save]. + /// + public static event RequestInitEventHandler AfterRequestInit; + /// + /// Raises the event. + /// + /// The instance containing the event data. + protected virtual void FireAfterRequestInit(RequestInitEventArgs e) + { + if (AfterRequestInit != null) + AfterRequestInit(this, e); + + } + } + + public class RequestInitEventArgs : System.ComponentModel.CancelEventArgs + { + public page Page { get; internal set; } + public HttpContext Context { get; internal set; } + public string Url { get; internal set; } + public int PageId { get; internal set; } + } } diff --git a/src/Umbraco.Web/umbraco.presentation/helper.cs b/src/Umbraco.Web/umbraco.presentation/helper.cs index 2f0f93a8cd..ac6ac83f50 100644 --- a/src/Umbraco.Web/umbraco.presentation/helper.cs +++ b/src/Umbraco.Web/umbraco.presentation/helper.cs @@ -126,6 +126,9 @@ namespace umbraco !string.IsNullOrEmpty(currentNode.FirstChild.Value) && !string.IsNullOrEmpty(currentNode.FirstChild.Value.Trim())) { + Umbraco.Core.Profiling.Profiler.Instance.Step("Loaded Recursively from " + + splitpath[ + splitpath.Length - i - 1]); HttpContext.Current.Trace.Write("parameter.recursive", "Item loaded from " + splitpath[splitpath.Length - i - 1]); attributeValue = currentNode.FirstChild.Value; break; diff --git a/src/Umbraco.Web/umbraco.presentation/item.cs b/src/Umbraco.Web/umbraco.presentation/item.cs index fe6c8faea7..6ac56cf993 100644 --- a/src/Umbraco.Web/umbraco.presentation/item.cs +++ b/src/Umbraco.Web/umbraco.presentation/item.cs @@ -7,191 +7,199 @@ using Umbraco.Core.Models; namespace umbraco { - /// - /// - /// - public class item - { - private String _fieldContent = ""; - private readonly String _fieldName; + /// + /// + /// + public class item + { + private String _fieldContent = ""; + private readonly String _fieldName; - public String FieldContent - { - get { return _fieldContent; } - } + public String FieldContent + { + get { return _fieldContent; } + } - public item(string itemValue, IDictionary attributes) - { - _fieldContent = itemValue; - ParseItem(attributes); - } + public item(string itemValue, IDictionary attributes) + { + _fieldContent = itemValue; + ParseItem(attributes); + } - /// - /// Creates a new Legacy item - /// - /// - /// + /// + /// Creates a new Legacy item + /// + /// + /// public item(IDictionary elements, IDictionary attributes) - : this(null, elements, attributes) - { - } + : this(null, elements, attributes) + { + } - /// - /// Creates an Item with a publishedContent item in order to properly recurse and return the value. - /// - /// - /// - /// - /// - /// THIS ENTIRE CLASS WILL BECOME LEGACY, THE FIELD RENDERING NEEDS TO BE REPLACES SO THAT IS WHY THIS - /// CTOR IS INTERNAL. - /// - internal item(IPublishedContent publishedContent, IDictionary elements, IDictionary attributes) - { - _fieldName = helper.FindAttribute(attributes, "field"); + /// + /// Creates an Item with a publishedContent item in order to properly recurse and return the value. + /// + /// + /// + /// + /// + /// THIS ENTIRE CLASS WILL BECOME LEGACY, THE FIELD RENDERING NEEDS TO BE REPLACES SO THAT IS WHY THIS + /// CTOR IS INTERNAL. + /// + internal item(IPublishedContent publishedContent, IDictionary elements, IDictionary attributes) + { + _fieldName = helper.FindAttribute(attributes, "field"); - if (_fieldName.StartsWith("#")) - { - _fieldContent = library.GetDictionaryItem(_fieldName.Substring(1, _fieldName.Length - 1)); - } - else - { - // Loop through XML children we need to find the fields recursive - if (helper.FindAttribute(attributes, "recursive") == "true") - { - if (publishedContent == null) - { - var recursiveVal = GetRecursiveValueLegacy(elements); - _fieldContent = recursiveVal.IsNullOrWhiteSpace() ? _fieldContent : recursiveVal; - } - else - { - var recursiveVal = publishedContent.GetRecursiveValue(_fieldName); - _fieldContent = recursiveVal.IsNullOrWhiteSpace() ? _fieldContent : recursiveVal; - } - } - else - { - if (elements[_fieldName] != null && !string.IsNullOrEmpty(elements[_fieldName].ToString())) - { - _fieldContent = elements[_fieldName].ToString().Trim(); - } - else if (!string.IsNullOrEmpty(helper.FindAttribute(attributes, "useIfEmpty"))) - { - if (elements[helper.FindAttribute(attributes, "useIfEmpty")] != null && !string.IsNullOrEmpty(elements[helper.FindAttribute(attributes, "useIfEmpty")].ToString())) - { - _fieldContent = elements[helper.FindAttribute(attributes, "useIfEmpty")].ToString().Trim(); - } - } + if (_fieldName.StartsWith("#")) + { + _fieldContent = library.GetDictionaryItem(_fieldName.Substring(1, _fieldName.Length - 1)); + } + else + { + // Loop through XML children we need to find the fields recursive + if (helper.FindAttribute(attributes, "recursive") == "true") + { + if (publishedContent == null) + { + var recursiveVal = GetRecursiveValueLegacy(elements); + _fieldContent = recursiveVal.IsNullOrWhiteSpace() ? _fieldContent : recursiveVal; + } + else + { + var recursiveVal = publishedContent.GetRecursiveValue(_fieldName); + _fieldContent = recursiveVal.IsNullOrWhiteSpace() ? _fieldContent : recursiveVal; + } + } + else + { + if (elements[_fieldName] != null && !string.IsNullOrEmpty(elements[_fieldName].ToString())) + { + _fieldContent = elements[_fieldName].ToString().Trim(); + } + else if (!string.IsNullOrEmpty(helper.FindAttribute(attributes, "useIfEmpty"))) + { + if (elements[helper.FindAttribute(attributes, "useIfEmpty")] != null && !string.IsNullOrEmpty(elements[helper.FindAttribute(attributes, "useIfEmpty")].ToString())) + { + _fieldContent = elements[helper.FindAttribute(attributes, "useIfEmpty")].ToString().Trim(); + } + } - } - } + } + } - ParseItem(attributes); - } + ParseItem(attributes); + } - /// - /// Returns the recursive value using a legacy strategy of looking at the xml cache and the splitPath in the elements collection - /// - /// - /// - private string GetRecursiveValueLegacy(IDictionary elements) - { - var content = ""; + /// + /// Returns the recursive value using a legacy strategy of looking at the xml cache and the splitPath in the elements collection + /// + /// + /// + private string GetRecursiveValueLegacy(IDictionary elements) + { + using (Umbraco.Core.Profiling.Profiler.Instance.Step("Checking recusively")) + { + var content = ""; - var umbracoXml = presentation.UmbracoContext.Current.GetXml(); + var umbracoXml = presentation.UmbracoContext.Current.GetXml(); - var splitpath = (String[])elements["splitpath"]; - for (int i = 0; i < splitpath.Length - 1; i++) - { - XmlNode element = umbracoXml.GetElementById(splitpath[splitpath.Length - i - 1]); + var splitpath = (String[])elements["splitpath"]; + for (int i = 0; i < splitpath.Length - 1; i++) + { + XmlNode element = umbracoXml.GetElementById(splitpath[splitpath.Length - i - 1]); - if (element == null) - continue; + if (element == null) + continue; - var xpath = UmbracoSettings.UseLegacyXmlSchema ? "./data [@alias = '{0}']" : "./{0}"; - var currentNode = element.SelectSingleNode(string.Format(xpath, _fieldName)); + var xpath = UmbracoSettings.UseLegacyXmlSchema ? "./data [@alias = '{0}']" : "./{0}"; + var currentNode = element.SelectSingleNode(string.Format(xpath, _fieldName)); - //continue if all is null - if (currentNode == null || currentNode.FirstChild == null || string.IsNullOrEmpty(currentNode.FirstChild.Value) || string.IsNullOrEmpty(currentNode.FirstChild.Value.Trim())) - continue; + //continue if all is null + if (currentNode == null || currentNode.FirstChild == null || string.IsNullOrEmpty(currentNode.FirstChild.Value) || string.IsNullOrEmpty(currentNode.FirstChild.Value.Trim())) + continue; - HttpContext.Current.Trace.Write("item.recursive", "Item loaded from " + splitpath[splitpath.Length - i - 1]); - content = currentNode.FirstChild.Value; - break; - } + Umbraco.Core.Profiling.Profiler.Instance.Step("Found recursive value on " + + splitpath[splitpath.Length - i - 1]); + HttpContext.Current.Trace.Write("item.recursive", "Item loaded from " + splitpath[splitpath.Length - i - 1]); + content = currentNode.FirstChild.Value; + break; + } - return content; - } + return content; + } + } private void ParseItem(IDictionary attributes) - { - HttpContext.Current.Trace.Write("item", "Start parsing '" + _fieldName + "'"); - if(helper.FindAttribute(attributes, "textIfEmpty") != "" && _fieldContent == "") - _fieldContent = helper.FindAttribute(attributes, "textIfEmpty"); + { + using (Umbraco.Core.Profiling.Profiler.Instance.Step("Start parsing " + _fieldName)) + { + HttpContext.Current.Trace.Write("item", "Start parsing '" + _fieldName + "'"); + if (helper.FindAttribute(attributes, "textIfEmpty") != "" && _fieldContent == "") + _fieldContent = helper.FindAttribute(attributes, "textIfEmpty"); - _fieldContent = _fieldContent.Trim(); + _fieldContent = _fieldContent.Trim(); - // DATE FORMATTING FUNCTIONS - if(helper.FindAttribute(attributes, "formatAsDateWithTime") == "true") - { - if(_fieldContent == "") - _fieldContent = DateTime.Now.ToString(); - _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString() + - helper.FindAttribute(attributes, "formatAsDateWithTimeSeparator") + - Convert.ToDateTime(_fieldContent).ToShortTimeString(); - } - else if(helper.FindAttribute(attributes, "formatAsDate") == "true") - { - if(_fieldContent == "") - _fieldContent = DateTime.Now.ToString(); - _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString(); - } + // DATE FORMATTING FUNCTIONS + if (helper.FindAttribute(attributes, "formatAsDateWithTime") == "true") + { + if (_fieldContent == "") + _fieldContent = DateTime.Now.ToString(); + _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString() + + helper.FindAttribute(attributes, "formatAsDateWithTimeSeparator") + + Convert.ToDateTime(_fieldContent).ToShortTimeString(); + } + else if (helper.FindAttribute(attributes, "formatAsDate") == "true") + { + if (_fieldContent == "") + _fieldContent = DateTime.Now.ToString(); + _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString(); + } - // TODO: Needs revision to check if parameter-tags has attributes - if(helper.FindAttribute(attributes, "stripParagraph") == "true" && _fieldContent.Length > 5) - { - _fieldContent = _fieldContent.Trim(); - string fieldContentLower = _fieldContent.ToLower(); + // TODO: Needs revision to check if parameter-tags has attributes + if (helper.FindAttribute(attributes, "stripParagraph") == "true" && _fieldContent.Length > 5) + { + _fieldContent = _fieldContent.Trim(); + string fieldContentLower = _fieldContent.ToLower(); // the field starts with an opening p tag - if (fieldContentLower.Substring(0, 3) == "

" - // it ends with a closing p tag - && fieldContentLower.Substring(_fieldContent.Length - 4, 4) == "

" - // it doesn't contain multiple p-tags - && fieldContentLower.IndexOf("

", 1) < 0) - { - _fieldContent = _fieldContent.Substring(3, _fieldContent.Length - 7); + if (fieldContentLower.Substring(0, 3) == "

" + // it ends with a closing p tag + && fieldContentLower.Substring(_fieldContent.Length - 4, 4) == "

" + // it doesn't contain multiple p-tags + && fieldContentLower.IndexOf("

", 1) < 0) + { + _fieldContent = _fieldContent.Substring(3, _fieldContent.Length - 7); + } } - } - // CASING - if (helper.FindAttribute(attributes, "case") == "lower") - _fieldContent = _fieldContent.ToLower(); - else if (helper.FindAttribute(attributes, "case") == "upper") - _fieldContent = _fieldContent.ToUpper(); - else if (helper.FindAttribute(attributes, "case") == "title") - _fieldContent = _fieldContent.ConvertCase(StringAliasCaseType.PascalCase); + // CASING + if (helper.FindAttribute(attributes, "case") == "lower") + _fieldContent = _fieldContent.ToLower(); + else if (helper.FindAttribute(attributes, "case") == "upper") + _fieldContent = _fieldContent.ToUpper(); + else if (helper.FindAttribute(attributes, "case") == "title") + _fieldContent = _fieldContent.ConvertCase(StringAliasCaseType.PascalCase); - // OTHER FORMATTING FUNCTIONS - // If we use masterpages, this is moved to the ItemRenderer to add support for before/after in inline XSLT - if (!UmbracoSettings.UseAspNetMasterPages) - { - if (_fieldContent != "" && helper.FindAttribute(attributes, "insertTextBefore") != "") - _fieldContent = HttpContext.Current.Server.HtmlDecode(helper.FindAttribute(attributes, "insertTextBefore")) + - _fieldContent; - if (_fieldContent != "" && helper.FindAttribute(attributes, "insertTextAfter") != "") - _fieldContent += HttpContext.Current.Server.HtmlDecode(helper.FindAttribute(attributes, "insertTextAfter")); + // OTHER FORMATTING FUNCTIONS + // If we use masterpages, this is moved to the ItemRenderer to add support for before/after in inline XSLT + if (!UmbracoSettings.UseAspNetMasterPages) + { + if (_fieldContent != "" && helper.FindAttribute(attributes, "insertTextBefore") != "") + _fieldContent = HttpContext.Current.Server.HtmlDecode(helper.FindAttribute(attributes, "insertTextBefore")) + + _fieldContent; + if (_fieldContent != "" && helper.FindAttribute(attributes, "insertTextAfter") != "") + _fieldContent += HttpContext.Current.Server.HtmlDecode(helper.FindAttribute(attributes, "insertTextAfter")); + } + if (helper.FindAttribute(attributes, "urlEncode") == "true") + _fieldContent = HttpUtility.UrlEncode(_fieldContent); + if (helper.FindAttribute(attributes, "htmlEncode") == "true") + _fieldContent = HttpUtility.HtmlEncode(_fieldContent); + if (helper.FindAttribute(attributes, "convertLineBreaks") == "true") + _fieldContent = _fieldContent.Replace("\n", "
\n"); + + HttpContext.Current.Trace.Write("item", "Done parsing '" + _fieldName + "'"); } - if(helper.FindAttribute(attributes, "urlEncode") == "true") - _fieldContent = HttpUtility.UrlEncode(_fieldContent); - if (helper.FindAttribute(attributes, "htmlEncode") == "true") - _fieldContent = HttpUtility.HtmlEncode(_fieldContent); - if(helper.FindAttribute(attributes, "convertLineBreaks") == "true") - _fieldContent = _fieldContent.Replace("\n", "
\n"); - - HttpContext.Current.Trace.Write("item", "Done parsing '" + _fieldName + "'"); - } - } + } + } } \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs index 0116b2f781..ebfc7ff742 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs @@ -23,269 +23,276 @@ using umbraco.IO; namespace umbraco.presentation.templateControls { - public class ItemRenderer - { - public readonly static ItemRenderer Instance = new ItemRenderer(); - ///

- /// Initializes a new instance of the class. - /// - protected ItemRenderer() - { } + public class ItemRenderer + { + public readonly static ItemRenderer Instance = new ItemRenderer(); + /// + /// Initializes a new instance of the class. + /// + protected ItemRenderer() + { } - /// - /// Renders the specified item. - /// - /// The item. - /// The writer. - public virtual void Render(Item item, HtmlTextWriter writer) - { - if (item.DebugMode) - { - writer.AddAttribute(HtmlTextWriterAttribute.Title, string.Format("Field Tag: '{0}'", item.Field)); - writer.AddAttribute("style", "border: 1px solid #fc6;"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - } + /// + /// Renders the specified item. + /// + /// The item. + /// The writer. + public virtual void Render(Item item, HtmlTextWriter writer) + { + if (item.DebugMode) + { + writer.AddAttribute(HtmlTextWriterAttribute.Title, string.Format("Field Tag: '{0}'", item.Field)); + writer.AddAttribute("style", "border: 1px solid #fc6;"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); + } - try - { - StringWriter renderOutputWriter = new StringWriter(); - HtmlTextWriter htmlWriter = new HtmlTextWriter(renderOutputWriter); - foreach (Control control in item.Controls) - { - try - { - control.RenderControl(htmlWriter); - } - catch (Exception renderException) - { - // TODO: Validate that the current control is within the scope of a form control - // Even controls that are inside this scope, can produce this error in async postback. - HttpContext.Current.Trace.Warn("ItemRenderer", - String.Format("Error rendering control {0} of {1}.", control.ClientID, item), renderException); - } - } + try + { + StringWriter renderOutputWriter = new StringWriter(); + HtmlTextWriter htmlWriter = new HtmlTextWriter(renderOutputWriter); + foreach (Control control in item.Controls) + { + try + { + control.RenderControl(htmlWriter); + } + catch (Exception renderException) + { + // TODO: Validate that the current control is within the scope of a form control + // Even controls that are inside this scope, can produce this error in async postback. + HttpContext.Current.Trace.Warn("ItemRenderer", + String.Format("Error rendering control {0} of {1}.", control.ClientID, item), renderException); + } + } - // parse macros and execute the XSLT transformation on the result if not empty - string renderOutput = renderOutputWriter.ToString(); - string xsltTransformedOutput = renderOutput.Trim().Length == 0 - ? String.Empty - : XsltTransform(item.Xslt, renderOutput, item.XsltDisableEscaping); - // handle text before/after - xsltTransformedOutput = AddBeforeAfterText(xsltTransformedOutput, helper.FindAttribute(item.LegacyAttributes, "insertTextBefore"), helper.FindAttribute(item.LegacyAttributes, "insertTextAfter")); - string finalResult = xsltTransformedOutput.Trim().Length > 0 ? xsltTransformedOutput : GetEmptyText(item); - writer.Write(TemplateUtilities.ResolveUrlsFromTextString(finalResult)); - } - catch (Exception renderException) - { - HttpContext.Current.Trace.Warn("ItemRenderer", String.Format("Error rendering {0}.", item), renderException); - } - finally - { - if (item.DebugMode) - { - writer.RenderEndTag(); - } - } - } + // parse macros and execute the XSLT transformation on the result if not empty + string renderOutput = renderOutputWriter.ToString(); + string xsltTransformedOutput = renderOutput.Trim().Length == 0 + ? String.Empty + : XsltTransform(item.Xslt, renderOutput, item.XsltDisableEscaping); + // handle text before/after + xsltTransformedOutput = AddBeforeAfterText(xsltTransformedOutput, helper.FindAttribute(item.LegacyAttributes, "insertTextBefore"), helper.FindAttribute(item.LegacyAttributes, "insertTextAfter")); + string finalResult = xsltTransformedOutput.Trim().Length > 0 ? xsltTransformedOutput : GetEmptyText(item); + writer.Write(TemplateUtilities.ResolveUrlsFromTextString(finalResult)); + } + catch (Exception renderException) + { + HttpContext.Current.Trace.Warn("ItemRenderer", String.Format("Error rendering {0}.", item), renderException); + } + finally + { + if (item.DebugMode) + { + writer.RenderEndTag(); + } + } + } - /// - /// Renders the field contents. - /// Checks via the NodeId attribute whether to fetch data from another page than the current one. - /// - /// A string of field contents (macros not parsed) - protected virtual string GetFieldContents(Item item) - { - var tempElementContent = string.Empty; + /// + /// Renders the field contents. + /// Checks via the NodeId attribute whether to fetch data from another page than the current one. + /// + /// A string of field contents (macros not parsed) + protected virtual string GetFieldContents(Item item) + { + var tempElementContent = string.Empty; - // if a nodeId is specified we should get the data from another page than the current one - if (string.IsNullOrEmpty(item.NodeId) == false) - { - var tempNodeId = item.GetParsedNodeId(); - if (tempNodeId != null && tempNodeId.Value != 0) - { + // if a nodeId is specified we should get the data from another page than the current one + if (string.IsNullOrEmpty(item.NodeId) == false) + { + var tempNodeId = item.GetParsedNodeId(); + if (tempNodeId != null && tempNodeId.Value != 0) + { //moved the following from the catch block up as this will allow fallback options alt text etc to work - var cache = Umbraco.Web.UmbracoContext.Current.ContentCache.InnerCache as PublishedContentCache; + var cache = Umbraco.Web.UmbracoContext.Current.ContentCache.InnerCache as PublishedContentCache; if (cache == null) throw new InvalidOperationException("Unsupported IPublishedContentCache, only the Xml one is supported."); - var xml = cache.GetXml(Umbraco.Web.UmbracoContext.Current, Umbraco.Web.UmbracoContext.Current.InPreviewMode); + var xml = cache.GetXml(Umbraco.Web.UmbracoContext.Current, Umbraco.Web.UmbracoContext.Current.InPreviewMode); var itemPage = new page(xml.GetElementById(tempNodeId.ToString())); tempElementContent = new item(itemPage.Elements, item.LegacyAttributes).FieldContent; - } - } - else - { - // gets the field content from the current page (via the PageElements collection) - tempElementContent = new item(item.PageElements, item.LegacyAttributes).FieldContent; - } + } + } + else + { + // gets the field content from the current page (via the PageElements collection) + tempElementContent = new item(item.PageElements, item.LegacyAttributes).FieldContent; + } - return tempElementContent; - } + return tempElementContent; + } - /// - /// Inits the specified item. To be called from the OnInit method of Item. - /// - /// The item. - public virtual void Init(Item item) - { } + /// + /// Inits the specified item. To be called from the OnInit method of Item. + /// + /// The item. + public virtual void Init(Item item) + { } - /// - /// Loads the specified item. To be called from the OnLoad method of Item. - /// - /// The item. - public virtual void Load(Item item) - { - ParseMacros(item); - } + /// + /// Loads the specified item. To be called from the OnLoad method of Item. + /// + /// The item. + public virtual void Load(Item item) + { + using (Umbraco.Core.Profiling.Profiler.Instance.Step(string.Format("Item: {0}", item.Field))) + { + ParseMacros(item); + } + } - /// - /// Parses the macros inside the text, by creating child elements for each item. - /// - /// The item. - protected virtual void ParseMacros(Item item) - { - // do nothing if the macros have already been rendered - if (item.Controls.Count > 0) - return; + /// + /// Parses the macros inside the text, by creating child elements for each item. + /// + /// The item. + protected virtual void ParseMacros(Item item) + { + // do nothing if the macros have already been rendered + if (item.Controls.Count > 0) + return; - string elementText = GetFieldContents(item); + string elementText = GetFieldContents(item); - MacroTagParser.ParseMacros( - elementText, + using (Umbraco.Core.Profiling.Profiler.Instance.Step("Parsing Macros")) + { - //callback for when a text block is parsed - textBlock => item.Controls.Add(new LiteralControl(textBlock)), + MacroTagParser.ParseMacros( + elementText, - //callback for when a macro is parsed: - (macroAlias, attributes) => - { - var macroControl = new Macro - { - Alias = macroAlias - }; - foreach (var i in attributes.Where(i => macroControl.Attributes[i.Key] == null)) - { - macroControl.Attributes.Add(i.Key, i.Value); - } - item.Controls.Add(macroControl); - }); - } + //callback for when a text block is parsed + textBlock => item.Controls.Add(new LiteralControl(textBlock)), - /// - /// Transforms the content using the XSLT attribute, if provided. - /// - /// The xpath expression. - /// The item's rendered content. - /// if set to true, escaping is disabled. - /// The transformed content if the XSLT attribute is present, otherwise the original content. - protected virtual string XsltTransform(string xpath, string itemData, bool disableEscaping) - { - if (!String.IsNullOrEmpty(xpath)) - { - // XML-encode the expression and add the itemData parameter to it - string xpathEscaped = xpath.Replace("<", "<").Replace(">", ">").Replace("\"", """); - string xpathExpression = string.Format(xpathEscaped, "$itemData"); + //callback for when a macro is parsed: + (macroAlias, attributes) => + { + var macroControl = new Macro + { + Alias = macroAlias + }; + foreach (var i in attributes.Where(i => macroControl.Attributes[i.Key] == null)) + { + macroControl.Attributes.Add(i.Key, i.Value); + } + item.Controls.Add(macroControl); + }); + } + } - // prepare support for XSLT extensions - StringBuilder namespaceList = new StringBuilder(); - StringBuilder namespaceDeclaractions = new StringBuilder(); - foreach (KeyValuePair extension in macro.GetXsltExtensions()) - { - namespaceList.Append(extension.Key).Append(' '); - namespaceDeclaractions.AppendFormat("xmlns:{0}=\"urn:{0}\" ", extension.Key); - } + /// + /// Transforms the content using the XSLT attribute, if provided. + /// + /// The xpath expression. + /// The item's rendered content. + /// if set to true, escaping is disabled. + /// The transformed content if the XSLT attribute is present, otherwise the original content. + protected virtual string XsltTransform(string xpath, string itemData, bool disableEscaping) + { + if (!String.IsNullOrEmpty(xpath)) + { + // XML-encode the expression and add the itemData parameter to it + string xpathEscaped = xpath.Replace("<", "<").Replace(">", ">").Replace("\"", """); + string xpathExpression = string.Format(xpathEscaped, "$itemData"); - // add the XSLT expression into the full XSLT document, together with the needed parameters + // prepare support for XSLT extensions + StringBuilder namespaceList = new StringBuilder(); + StringBuilder namespaceDeclaractions = new StringBuilder(); + foreach (KeyValuePair extension in macro.GetXsltExtensions()) + { + namespaceList.Append(extension.Key).Append(' '); + namespaceDeclaractions.AppendFormat("xmlns:{0}=\"urn:{0}\" ", extension.Key); + } + + // add the XSLT expression into the full XSLT document, together with the needed parameters string xslt = string.Format(Umbraco.Web.umbraco.presentation.umbraco.templateControls.Resources.InlineXslt, xpathExpression, disableEscaping ? "yes" : "no", - namespaceList, namespaceDeclaractions); + namespaceList, namespaceDeclaractions); - // create the parameter - Dictionary parameters = new Dictionary(1); - parameters.Add("itemData", itemData); + // create the parameter + Dictionary parameters = new Dictionary(1); + parameters.Add("itemData", itemData); - // apply the XSLT transformation - XmlTextReader xslReader = new XmlTextReader(new StringReader(xslt)); - System.Xml.Xsl.XslCompiledTransform xsl = macro.CreateXsltTransform(xslReader, false); - itemData = macro.GetXsltTransformResult(new XmlDocument(), xsl, parameters); - xslReader.Close(); - } - return itemData; - } + // apply the XSLT transformation + XmlTextReader xslReader = new XmlTextReader(new StringReader(xslt)); + System.Xml.Xsl.XslCompiledTransform xsl = macro.CreateXsltTransform(xslReader, false); + itemData = macro.GetXsltTransformResult(new XmlDocument(), xsl, parameters); + xslReader.Close(); + } + return itemData; + } - protected string AddBeforeAfterText(string text, string before, string after) - { - if (!String.IsNullOrEmpty(text)) - { - if (!String.IsNullOrEmpty(before)) - text = String.Format("{0}{1}", HttpContext.Current.Server.HtmlDecode(before), text); - if (!String.IsNullOrEmpty(after)) - text = String.Format("{0}{1}", text, HttpContext.Current.Server.HtmlDecode(after)); - } + protected string AddBeforeAfterText(string text, string before, string after) + { + if (!String.IsNullOrEmpty(text)) + { + if (!String.IsNullOrEmpty(before)) + text = String.Format("{0}{1}", HttpContext.Current.Server.HtmlDecode(before), text); + if (!String.IsNullOrEmpty(after)) + text = String.Format("{0}{1}", text, HttpContext.Current.Server.HtmlDecode(after)); + } - return text; - } + return text; + } - /// - /// Gets the text to display if the field contents are empty. - /// - /// The item. - /// The text to display. - protected virtual string GetEmptyText(Item item) - { - return item.TextIfEmpty; - } + /// + /// Gets the text to display if the field contents are empty. + /// + /// The item. + /// The text to display. + protected virtual string GetEmptyText(Item item) + { + return item.TextIfEmpty; + } - /// - /// Gets the field content from database instead of the published XML via the APIs. - /// - /// - /// The node id. - /// The field that should be fetched. - /// The contents of the from the content object - [Obsolete("This is no longer used in the codebase and will be removed in future versions")] + /// + /// Gets the field content from database instead of the published XML via the APIs. + /// + /// + /// The node id. + /// The field that should be fetched. + /// The contents of the from the content object + [Obsolete("This is no longer used in the codebase and will be removed in future versions")] protected virtual string GetContentFromDatabase(AttributeCollectionAdapter itemAttributes, int nodeIdInt, string currentField) - { - var c = new Content(nodeIdInt); + { + var c = new Content(nodeIdInt); - var property = c.getProperty(currentField); - if (property == null) - throw new ArgumentException(String.Format("Could not find property {0} of node {1}.", currentField, nodeIdInt)); + var property = c.getProperty(currentField); + if (property == null) + throw new ArgumentException(String.Format("Could not find property {0} of node {1}.", currentField, nodeIdInt)); - var umbItem = new item(property.Value.ToString(), itemAttributes); - var tempElementContent = umbItem.FieldContent; + var umbItem = new item(property.Value.ToString(), itemAttributes); + var tempElementContent = umbItem.FieldContent; - // If the current content object is a document object, we'll only output it if it's published - if (c.nodeObjectType == Document._objectType) - { - try - { - var d = (Document)c; - if (!d.Published) - tempElementContent = ""; - } - catch { } - } + // If the current content object is a document object, we'll only output it if it's published + if (c.nodeObjectType == Document._objectType) + { + try + { + var d = (Document)c; + if (!d.Published) + tempElementContent = ""; + } + catch { } + } - // Add the content to the cache - if (!string.IsNullOrEmpty(tempElementContent)) - { - ApplicationContext.Current.ApplicationCache.InsertCacheItem( - string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt, currentField), - CacheItemPriority.Default, () => tempElementContent); - } - return tempElementContent; - } + // Add the content to the cache + if (!string.IsNullOrEmpty(tempElementContent)) + { + ApplicationContext.Current.ApplicationCache.InsertCacheItem( + string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt, currentField), + CacheItemPriority.Default, () => tempElementContent); + } + return tempElementContent; + } - /// - /// Gets the content from cache. - /// - /// The node id. - /// The field. + /// + /// Gets the content from cache. + /// + /// The node id. + /// The field. /// The cached contents of the from the content object [Obsolete("This is no longer used in the codebase and will be removed in future versions")] - protected virtual object GetContentFromCache(int nodeIdInt, string field) - { - var content = ApplicationContext.Current.ApplicationCache.GetCacheItem( + protected virtual object GetContentFromCache(int nodeIdInt, string field) + { + var content = ApplicationContext.Current.ApplicationCache.GetCacheItem( string.Format("{0}{1}_{2}", CacheKeys.ContentItemCacheKey, nodeIdInt, field)); - return content; - } - } + return content; + } + } }