diff --git a/umbraco/presentation/macro.cs b/umbraco/presentation/macro.cs index ae1d9e5215..89db4fbf33 100644 --- a/umbraco/presentation/macro.cs +++ b/umbraco/presentation/macro.cs @@ -368,24 +368,38 @@ namespace umbraco String macroHtml = null; Control macroControl = null; - // zb-00037 #29875 : parse attributes here (and before anything else) - foreach (var prop in model.Properties) - prop.Value = helper.parseAttribute(pageElements, prop.Value); + // zb-00037 #29875 : parse attributes here (and before anything else) + foreach (var prop in model.Properties) + prop.Value = helper.parseAttribute(pageElements, prop.Value); model.CacheIdentifier = getCacheGuid(model, pageElements, pageId); if (model.CacheDuration > 0) { - macroHtml = macroCache["macroHtml_" + model.CacheIdentifier] as String; - - if (!String.IsNullOrEmpty(macroHtml)) + if (cacheMacroAsString(model)) { macroHtml = macroCache["macroHtml_" + model.CacheIdentifier] as String; - HttpContext.Current.Trace.Write("renderMacro", "Content loaded from cache ('" + model.CacheIdentifier + "')..."); + + if (!String.IsNullOrEmpty(macroHtml)) + { + macroHtml = macroCache["macroHtml_" + model.CacheIdentifier] as String; + HttpContext.Current.Trace.Write("renderMacro", "Macro Content loaded from cache ('" + model.CacheIdentifier + "')..."); + } + } + else + { + if (macroCache["macroControl_" + model.CacheIdentifier] != null) + { + MacroCacheContent cacheContent = (MacroCacheContent)macroCache["macroControl_" + model.CacheIdentifier]; + macroControl = cacheContent.Content; + macroControl.ID = cacheContent.ID; + HttpContext.Current.Trace.Write("renderMacro", "Macro Control loaded from cache ('" + model.CacheIdentifier + "')..."); + } + } } - if (String.IsNullOrEmpty(macroHtml)) + if (String.IsNullOrEmpty(macroHtml) && macroControl == null) { int macroType = model.MacroType != MacroTypes.Unknown ? (int)model.MacroType : MacroType; switch (macroType) @@ -475,29 +489,40 @@ namespace umbraco { if (macroControl != null) { - using (var sw = new StringWriter()) + // NH: Scripts and XSLT can be generated as strings, but not controls as page events wouldn't be hit (such as Page_Load, etc) + if (cacheMacroAsString(model)) { - var hw = new HtmlTextWriter(sw); - macroControl.RenderControl(hw); + using (var sw = new StringWriter()) + { + var hw = new HtmlTextWriter(sw); + macroControl.RenderControl(hw); - macroCache.Insert("macroHtml_" + model.CacheIdentifier, - sw.ToString(), - null, - DateTime.Now.AddSeconds(model.CacheDuration), - TimeSpan.Zero, - CacheItemPriority.Low, - null); + macroCache.Insert("macroHtml_" + model.CacheIdentifier, + sw.ToString(), + null, + DateTime.Now.AddSeconds(model.CacheDuration), + TimeSpan.Zero, + CacheItemPriority.Low, + null); + + // zb-00003 #29470 : replace by text if not already text + // otherwise it is rendered twice + if (!(macroControl is LiteralControl)) + macroControl = new LiteralControl(sw.ToString()); + } + } + else + { + macroCache.Insert("macroControl_" + model.CacheIdentifier, new MacroCacheContent(macroControl, macroControl.ID), null, + DateTime.Now.AddSeconds(model.CacheDuration), TimeSpan.Zero, CacheItemPriority.Low, + null); - // zb-00003 #29470 : replace by text if not already text - // otherwise it is rendered twice - if (!(macroControl is LiteralControl)) - macroControl = new LiteralControl(sw.ToString()); } } } } } - else + else if (macroControl == null) { macroControl = new LiteralControl(macroHtml); } @@ -505,6 +530,11 @@ namespace umbraco return macroControl; } + private bool cacheMacroAsString(MacroModel model) + { + return model.MacroType == MacroTypes.XSLT || model.MacroType == MacroTypes.Python; + } + public static XslCompiledTransform getXslt(string XsltFile) { if (HttpRuntime.Cache["macroXslt_" + XsltFile] != null) @@ -604,7 +634,7 @@ namespace umbraco foreach (DictionaryEntry macroDef in macro.properties) { var prop = model.Properties.Find(m => m.Key == (string)macroDef.Key.ToString().ToLower()); - // zb-00037 #29875 : values have already been parsed + no need to parse "" + // zb-00037 #29875 : values have already been parsed + no need to parse "" string propValue = prop != null ? prop.Value : ""; if (!String.IsNullOrEmpty(propValue)) { @@ -761,27 +791,27 @@ namespace umbraco /// Gets a collection of all XSLT extensions for macros, including predefined extensions. /// /// A dictionary of name/extension instance pairs. - public static Dictionary GetXsltExtensions() - { - // zb-00041 #29966 : cache the extensions + public static Dictionary GetXsltExtensions() + { + // zb-00041 #29966 : cache the extensions - // We could cache the extensions in a static variable but then the cache - // would not be refreshed when the .config file is modified. An application - // restart would be required. Better use the cache and add a dependency. + // We could cache the extensions in a static variable but then the cache + // would not be refreshed when the .config file is modified. An application + // restart would be required. Better use the cache and add a dependency. - return umbraco.cms.businesslogic.cache.Cache.GetCacheItem( - _xsltExtensionsCacheKey, _xsltExtensionsSyncLock, - CacheItemPriority.Normal, // normal priority - null, // no refresh action - new CacheDependency(_xsltExtensionsConfig), // depends on the .config file - TimeSpan.FromDays(1), // expires in 1 day (?) - () => { return GetXsltExtensionsImpl(); }); - } + return umbraco.cms.businesslogic.cache.Cache.GetCacheItem( + _xsltExtensionsCacheKey, _xsltExtensionsSyncLock, + CacheItemPriority.Normal, // normal priority + null, // no refresh action + new CacheDependency(_xsltExtensionsConfig), // depends on the .config file + TimeSpan.FromDays(1), // expires in 1 day (?) + () => { return GetXsltExtensionsImpl(); }); + } - // zb-00041 #29966 : cache the extensions - const string _xsltExtensionsCacheKey = "UmbracoXsltExtensions"; - static string _xsltExtensionsConfig = IOHelper.MapPath(SystemDirectories.Config + "/xsltExtensions.config"); - static object _xsltExtensionsSyncLock = new object(); + // zb-00041 #29966 : cache the extensions + const string _xsltExtensionsCacheKey = "UmbracoXsltExtensions"; + static string _xsltExtensionsConfig = IOHelper.MapPath(SystemDirectories.Config + "/xsltExtensions.config"); + static object _xsltExtensionsSyncLock = new object(); static Dictionary GetXsltExtensionsImpl() { @@ -790,7 +820,7 @@ namespace umbraco // Load the XSLT extensions configuration var xsltExt = new XmlDocument(); - xsltExt.Load(_xsltExtensionsConfig); + xsltExt.Load(_xsltExtensionsConfig); // add all descendants of the XsltExtensions element foreach (XmlNode xsltEx in xsltExt.SelectSingleNode("/XsltExtensions")) @@ -834,14 +864,14 @@ namespace umbraco //also get types marked with XsltExtension attribute - // zb-00042 #29949 : do not hide errors, refactor + // zb-00042 #29949 : do not hide errors, refactor foreach (Type xsltType in BusinessLogic.Utils.TypeFinder.FindClassesMarkedWithAttribute(typeof(XsltExtensionAttribute))) { object[] tpAttributes = xsltType.GetCustomAttributes(typeof(XsltExtensionAttribute), true); foreach (XsltExtensionAttribute tpAttribute in tpAttributes) { - string ns = !string.IsNullOrEmpty(tpAttribute.Namespace) ? tpAttribute.Namespace : xsltType.FullName; - extensions.Add(ns, Activator.CreateInstance(xsltType)); + string ns = !string.IsNullOrEmpty(tpAttribute.Namespace) ? tpAttribute.Namespace : xsltType.FullName; + extensions.Add(ns, Activator.CreateInstance(xsltType)); } } @@ -1112,8 +1142,8 @@ namespace umbraco } MacroPropertyModel propModel = model.Properties.Find(m => m.Key == propertyAlias.ToLower()); - // zb-00037 #29875 : values have already been parsed + no need to parse "" - object propValue = prop != null ? propModel.Value : ""; + // zb-00037 #29875 : values have already been parsed + no need to parse "" + object propValue = prop != null ? propModel.Value : ""; // Special case for types of webControls.unit if (prop.PropertyType == typeof(Unit)) propValue = Unit.Parse(propValue.ToString()); @@ -1205,8 +1235,8 @@ namespace umbraco } MacroPropertyModel propModel = model.Properties.Find(m => m.Key == propertyAlias.ToLower()); - // zb-00037 #29875 : values have already been parsed + no need to parse "" - object propValue = prop != null ? propModel.Value : ""; + // zb-00037 #29875 : values have already been parsed + no need to parse "" + object propValue = prop != null ? propModel.Value : ""; if (propValue == null) continue; @@ -1400,8 +1430,8 @@ namespace umbraco var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url); // propagate the user's context - // zb-00004 #29956 : refactor cookies names & handling - HttpCookie inCookie = StateHelper.Cookies.UserContext.RequestCookie; + // zb-00004 #29956 : refactor cookies names & handling + HttpCookie inCookie = StateHelper.Cookies.UserContext.RequestCookie; var cookie = new Cookie(inCookie.Name, inCookie.Value, inCookie.Path, HttpContext.Current.Request.ServerVariables["SERVER_NAME"]); myHttpWebRequest.CookieContainer = new CookieContainer();