public Control RenderMacro(Hashtable pageElements, int documentId) { TraceInfo("renderMacro", string.Format("Rendering started (macro: {0}, type: {1}, cacheRate: {2})", Name, MacroType, Model.CacheDuration)); StateHelper.SetContextValue(MacrosAddedKey, StateHelper.GetContextValue <int>(MacrosAddedKey) + 1); 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); } Model.CacheIdentifier = GetCacheIdentifier(Model); if (Model.CacheDuration > 0) { if (CacheMacroAsString(Model)) { macroHtml = _macroCache["macroHtml_" + Model.CacheIdentifier] as String; // FlorisRobbemont: // An empty string means: macroHtml has been cached before, but didn't had any output (Macro doesn't need to be rendered again) // An empty reference (null) means: macroHtml has NOT been cached before if (macroHtml != null) { if (MacroNeedsToBeClearedFromCache(Model, "macroHtml_DateAdded_" + Model.CacheIdentifier)) { macroHtml = null; TraceInfo("renderMacro", string.Format("Macro removed from cache due to file change '{0}'.", Model.CacheIdentifier)); } else { TraceInfo("renderMacro", string.Format("Macro Content loaded from cache '{0}'.", Model.CacheIdentifier)); } } } else { var cacheContent = _macroCache["macroControl_" + Model.CacheIdentifier] as MacroCacheContent; if (cacheContent != null) { macroControl = cacheContent.Content; macroControl.ID = cacheContent.ID; if (MacroNeedsToBeClearedFromCache(Model, "macroControl_DateAdded_" + Model.CacheIdentifier)) { TraceInfo("renderMacro", string.Format("Macro removed from cache due to file change '{0}'.", Model.CacheIdentifier)); macroControl = null; } else { TraceInfo("renderMacro", string.Format("Macro Control loaded from cache '{0}'.", Model.CacheIdentifier)); } } } } // FlorisRobbemont: Empty macroHtml (not null, but "") doesn't mean a re-render is necessary if (macroHtml == null && macroControl == null) { var renderFailed = false; var macroType = Model.MacroType != MacroTypes.Unknown ? (int)Model.MacroType : MacroType; switch (macroType) { case (int)MacroTypes.XSLT: macroControl = loadMacroXSLT(this, Model, pageElements); break; case (int)MacroTypes.Script: try { TraceInfo("umbracoMacro", "MacroEngine script added (" + ScriptFile + ")"); var result = LoadMacroScript(Model, documentId); macroControl = new LiteralControl(result.Result); if (result.ResultException != null) { // we'll throw the error if we run in release mode, show details if we're in release mode! renderFailed = true; if (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled) { throw result.ResultException; } } break; } catch (Exception e) { renderFailed = true; Exceptions.Add(e); Log.Instance.LogError("RenderMacro: " + e); var result = new LiteralControl("Error loading MacroEngine script (file: " + ScriptFile + ")"); macroControl = result; break; } default: if (GlobalSettings.DebugMode) { macroControl = new LiteralControl("<Macro: " + Name + " (" + ScriptAssembly + "," + ScriptType + ")>"); } break; } // Add result to cache if successful if (!renderFailed && Model.CacheDuration > 0) { // do not add to cache if there's no member and it should cache by personalization if (!Model.CacheByMember || (Model.CacheByMember && Member.GetCurrentMember() != null)) { if (macroControl != null) { // 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)) { string outputCacheString; using (var sw = new StringWriter()) { var hw = new HtmlTextWriter(sw); macroControl.RenderControl(hw); outputCacheString = sw.ToString(); } _macroCache.Insert("macroHtml_" + Model.CacheIdentifier, outputCacheString, null, DateTime.Now.AddSeconds(Model.CacheDuration), TimeSpan.Zero, CacheItemPriority.NotRemovable, //FlorisRobbemont: issue #27610 -> Macro output cache should not be removable null); _macroCache.Insert("macroHtml_DateAdded_" + Model.CacheIdentifier, DateTime.Now, null, DateTime.Now.AddSeconds(Model.CacheDuration), TimeSpan.Zero, CacheItemPriority.NotRemovable, //FlorisRobbemont: issue #27610 -> Macro output cache should not be removable null); // zb-00003 #29470 : replace by text if not already text // otherwise it is rendered twice if (!(macroControl is LiteralControl)) { macroControl = new LiteralControl(outputCacheString); } TraceInfo("renderMacro", string.Format("Macro Content saved to cache '{0}'.", Model.CacheIdentifier)); } else { _macroCache.Insert("macroControl_" + Model.CacheIdentifier, new MacroCacheContent(macroControl, macroControl.ID), null, DateTime.Now.AddSeconds(Model.CacheDuration), TimeSpan.Zero, CacheItemPriority.NotRemovable, //FlorisRobbemont: issue #27610 -> Macro output cache should not be removable null); _macroCache.Insert("macroControl_DateAdded_" + Model.CacheIdentifier, DateTime.Now, null, DateTime.Now.AddSeconds(Model.CacheDuration), TimeSpan.Zero, CacheItemPriority.NotRemovable, //FlorisRobbemont: issue #27610 -> Macro output cache should not be removable null); TraceInfo("renderMacro", string.Format("Macro Control saved to cache '{0}'.", Model.CacheIdentifier)); } } } } } else if (macroControl == null) { macroControl = new LiteralControl(macroHtml); } return(macroControl); }