Try our conversational search powered by Generative AI!

Issue with TagBuilder inside CustomContentAreaRenderer

Vote:
 

In previous CMS 11.x version, I can modify ContentAreaRenderer result with codes bellow without any problems:

public class AlloyContentAreaItemRenderer : ContentAreaRenderer
{
    protected override void RenderContentAreaItem(IHtmlHelper htmlHelper, ContentAreaItem contentAreaItem, string templateTag, string htmlTag, string cssClass)
    {
        var originalWriter = htmlHelper.ViewContext.Writer;
        var tempWriter = new StringWriter();
        htmlHelper.ViewContext.Writer = tempWriter;
        try
        {
            base.RenderContentAreaItem(htmlHelper, contentAreaItem, templateTag, htmlTag, cssClass);
            
            var contentItemContent = tempWriter.ToString();
            
            // Modify content area html result (ex: Remove all comment, add custom tag ...)
            var doc = new HtmlDocument();
            doc.Load(new StringReader(contentItemContent));
            
            // Write modified result to main writer
            originalWriter.Write(contentItemContent);
        }
        finally
        {
            // Restore original writer to proceed further with rest of the rendering
            htmlHelper.ViewContext.Writer = originalWriter;
        }
    }
}

After upgrade to CMS 12 versions, the result I get from tempWriter.ToString() always contain TagBuilder type at start and end of result as captured image.

Go inside base.RenderContentAreaItem, i think the problem come from these lines htmlHelper.ViewContext.Writer.Write((object) ...) , i think this need write raw html result.

using (new ContentRenderingScope(htmlHelper.ViewContext.HttpContext, contentData, templateModel, templateTags))
{
        TagBuilder tagBuilder = new TagBuilder(htmlTag);
        this.AddNonEmptyCssClass(tagBuilder, cssClass);
        tagBuilder.MergeAttributes<string, string>(this._attributeAssembler.GetAttributes(contentAreaItem, this.IsInEditMode(), templateModel != null));
        this.BeforeRenderContentAreaItemStartTag(tagBuilder, contentAreaItem);
        htmlHelper.ViewContext.Writer.Write((object) tagBuilder.RenderStartTag());
        htmlHelper.RenderContentData(contentData, true, templateModel, this._contentRenderer);
        htmlHelper.ViewContext.Writer.Write((object) tagBuilder.RenderEndTag());
}
#299525
Edited, Apr 04, 2023 16:32
Vote:
 

It seems that you circumvent lots of logic when you change the writer. One alternative is to wrap the original writer and try to catch whatever that's written to it. Not sure about side effects.

Try the class below and assign it to tempWriter variable instead.

var tempWriter = new CustomTextWriter(htmlHelper.ViewContext.Writer);

As next step, fetch the HTML using this code:

using (var writer = new StringWriter())
{
    tempWriter.GetHtmlContent().WriteTo(writer, HtmlEncoder.Default);

    var contentItemContent = new HtmlString(writer.ToString());
}
public class CustomTextWriter : TextWriter
{
    private readonly TextWriter _wrappedWriter;
    private readonly StringBuilder _sb;

    public CustomTextWriter(TextWriter wrappedWriter)
    {
        _wrappedWriter = wrappedWriter;
        _sb = new StringBuilder();
    }

    public override Encoding Encoding => _wrappedWriter.Encoding;

    public override void Write(char value)
    {
        _wrappedWriter.Write(value);

        _sb.Append(value);
    }

    public override void Write(object value)
    {
        _wrappedWriter.Write(value);
    }

    public override void Flush()
    {
        _wrappedWriter.Flush();
    }

    public override Task FlushAsync()
    {
        return _wrappedWriter.FlushAsync();
    }

    protected override void Dispose(bool disposing)
    {
        _wrappedWriter.Dispose();
    }

    public override ValueTask DisposeAsync()
    {
        return _wrappedWriter.DisposeAsync();
    }

    public IHtmlContent GetHtmlContent()
    {
        return new HelperResult(writer => writer.WriteAsync(_sb));
    }
}
#300118
Edited, Apr 14, 2023 8:13
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.