2

I'm working on an Html Helper to create a control that will consist of multiple elements, build using TagBuilders. The control itself will be rendered using a TagBuilder that contains a div with all child elements.

Per this: https://developercommunity.visualstudio.com/content/problem/17287/tagbuilder-tostring-returns-the-type-of-tagbuilder.html

I implemented a Render() method to create the control and return it as a string:

public class MyCustomControl
{
    public override string ToString()
    {
        return Render();
    }

    private string Render()
    {
        TagBuilder mainContainer = new TagBuilder("div");

        // Generate child elements and append to mainContainer...

        using (StringWriter writer = new StringWriter())
        {
            mainContainer.WriteTo(writer, HtmlEncoder.Default);

            return writer.ToString();
        }
    }
}

And made an extension method to call it in a Razor View:

public static MyCustomControl(this IHtmlHelper html)
{
    return new MyCustomControl();
}

And include it in Views like this:

@(Html.MyCustomControl()
)

The problem is instead of being rendered html, I get raw html text output to the View, so I actually see:

<div><!-- all child controls html here --></div>

Instead of there being an element there.

2
  • 1
    You’re describing the opposite; you’re outputting HTML encoded text so that you see what looks like HTML on your page. You want to output raw HTML in this case so remove the encoding. Commented Oct 3, 2018 at 21:16
  • TagBuilder.WriteTo requires an HtmlEncoder and Default is the only implementation available. Commented Oct 3, 2018 at 21:35

2 Answers 2

5

You need to return an instance of IHtmlContent instead of string :

public static class HtmlHelperExtension {
    public static IHtmlContent MyCustomControl(this IHtmlHelper html)
    {
        var result = new MyCustomControl();
        return html.Raw(result.Render());
    }
}

Test Case :

public class MyCustomControl
{
    public override string ToString()
    {
        return Render();
    }

    public string Render()
    {
        TagBuilder mainContainer = new TagBuilder("div");
        mainContainer.Attributes.Add(new KeyValuePair<string, string>("data-id","123") );

        // Generate child elements and append to mainContainer...

        using (StringWriter writer = new StringWriter())
        {
            mainContainer.WriteTo(writer, HtmlEncoder.Default);

            var result=writer.ToString();
            return result;
        }
    }

the result will be :

<div data-id="123"></div>
Sign up to request clarification or add additional context in comments.

Comments

0

I believe a better way to do this is to implement IHtmlContent in your custom control, like so:

public class MyCustomControl : IHtmlContent
{
    public void WriteTo(TextWriter writer, HtmlEncoder encoder)
    {
        TagBuilder mainContainer = new TagBuilder("div");

        // Generate child elements and append to mainContainer...

        mainContainer.WriteTo(writer, encoder);
    }
}

then your HtmlHelper extension doesn't change all that much:

public static IHtmlContent MyCustomControl(this IHtmlHelper html)
{
    return new MyCustomControl();
}

This should eliminate the temporary strings which are created in the accepted answer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.