private string RenderMacro(MacroBlockTag macroBlockTag, IEnumerable <Option <ILiquidValue> > args) { var macroRenderer = new MacroRenderer(); var expressionConstant = (ILiquidValue)macroRenderer.Render(this, macroBlockTag, _templateContext, args.ToList()); return(ValueCaster.RenderAsString(expressionConstant)); }
/// <summary> /// Renders the macro with the specified alias, passing in the specified parameters. /// </summary> /// <param name="m">The macro.</param> /// <param name="parameters">The parameters.</param> /// <param name="umbracoPage">The legacy umbraco page object that is required for some macros</param> /// <returns></returns> internal IHtmlString RenderMacro(MacroModel m, IDictionary <string, object> parameters, page umbracoPage) { if (umbracoPage == null) { throw new ArgumentNullException(nameof(umbracoPage)); } if (m == null) { throw new ArgumentNullException(nameof(m)); } if (_umbracoContext.PageId == null) { throw new InvalidOperationException("Cannot render a macro when UmbracoContext.PageId is null."); } var macroProps = new Hashtable(); foreach (var i in parameters) { //TODO: We are doing at ToLower here because for some insane reason the UpdateMacroModel method of macro.cs // looks for a lower case match. WTF. the whole macro concept needs to be rewritten. //NOTE: the value could have html encoded values, so we need to deal with that macroProps.Add(i.Key.ToLowerInvariant(), (i.Value is string) ? HttpUtility.HtmlDecode(i.Value.ToString()) : i.Value); } var renderer = new MacroRenderer(Current.ProfilingLogger); var macroControl = renderer.Render(m, umbracoPage.Elements, _umbracoContext.PageId.Value, macroProps).GetAsControl(); string html; if (macroControl is LiteralControl) { // no need to execute, we already have text html = (macroControl as LiteralControl).Text; } else { var containerPage = new FormlessPage(); containerPage.Controls.Add(macroControl); using (var output = new StringWriter()) { // .Execute() does a PushTraceContext/PopTraceContext and writes trace output straight into 'output' // and I do not see how we could wire the trace context to the current context... so it creates dirty // trace output right in the middle of the page. // // The only thing we can do is fully disable trace output while .Execute() runs and restore afterwards // which means trace output is lost if the macro is a control (.ascx or user control) that is invoked // from within Razor -- which makes sense anyway because the control can _not_ run correctly from // within Razor since it will never be inserted into the page pipeline (which may even not exist at all // if we're running MVC). // // I'm sure there's more things that will get lost with this context changing but I guess we'll figure // those out as we go along. One thing we lose is the content type response output. // http://issues.umbraco.org/issue/U4-1599 if it is setup during the macro execution. So // here we'll save the content type response and reset it after execute is called. var contentType = _umbracoContext.HttpContext.Response.ContentType; var traceIsEnabled = containerPage.Trace.IsEnabled; containerPage.Trace.IsEnabled = false; _umbracoContext.HttpContext.Server.Execute(containerPage, output, true); containerPage.Trace.IsEnabled = traceIsEnabled; //reset the content type _umbracoContext.HttpContext.Response.ContentType = contentType; //Now, we need to ensure that local links are parsed html = TemplateUtilities.ParseInternalLinks(output.ToString(), _umbracoContext.UrlProvider); } } return(new HtmlString(html)); }
/// <summary> /// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering. /// </summary> protected override void CreateChildControls() { // collect all attributes set on the control var keys = Attributes.Keys; foreach (string key in keys) { MacroAttributes.Add(key.ToLower(), HttpUtility.HtmlDecode(Attributes[key])); } if (MacroAttributes.ContainsKey("macroalias") == false && MacroAttributes.ContainsKey("macroAlias") == false) { MacroAttributes.Add("macroalias", Alias); } // set pageId to int.MinValue if no pageID was found, // e.g. if the macro was rendered on a custom (non-Umbraco) page var pageId = UmbracoContext.Current.PageId == null ? int.MinValue : UmbracoContext.Current.PageId.Value; if ((string.IsNullOrEmpty(Language) == false && Text != "") || string.IsNullOrEmpty(FileLocation) == false) { var tempMacro = new MacroModel(); MacroRenderer.GenerateMacroModelPropertiesFromAttributes(tempMacro, MacroAttributes); // executing an inline macro? // ie the code of the macro is in the control's text body // ok, this is not supported in v8 anymore if (string.IsNullOrEmpty(FileLocation)) { throw new NotSupportedException("Inline macros are not supported anymore."); } // executing an on-disk macro // it has to be a partial (cshtml or vbhtml) macro in v8 var extension = System.IO.Path.GetExtension(FileLocation); if (extension.InvariantEndsWith(".cshtml") == false && extension.InvariantEndsWith(".vbhtml") == false) { throw new NotSupportedException(""); } tempMacro.MacroSource = FileLocation; tempMacro.MacroType = MacroTypes.PartialView; if (string.IsNullOrEmpty(Attributes["Cache"]) == false) { int cacheDuration; if (int.TryParse(Attributes["Cache"], out cacheDuration)) { tempMacro.CacheDuration = cacheDuration; } else { Context.Trace.Warn("Template", "Cache attribute is in incorect format (should be an integer)."); } } var renderer = new MacroRenderer(Current.ProfilingLogger); var c = renderer.Render(tempMacro, (Hashtable)Context.Items["pageElements"], pageId).GetAsControl(); if (c != null) { Exceptions = renderer.Exceptions; Controls.Add(c); } else { Context.Trace.Warn("Template", "Result of inline macro scripting is null"); } } else { var m = Current.Services.MacroService.GetByAlias(Alias); if (m == null) { return; } var tempMacro = new MacroModel(m); try { var renderer = new MacroRenderer(Current.ProfilingLogger); var c = renderer.Render(tempMacro, (Hashtable)Context.Items["pageElements"], pageId, MacroAttributes).GetAsControl(); if (c != null) { Controls.Add(c); } else { Context.Trace.Warn("Template", "Result of macro " + tempMacro.Name + " is null"); } } catch (Exception ee) { Context.Trace.Warn("Template", "Error adding macro " + tempMacro.Name, ee); throw; } } }