Search code examples
asp.netasp.net-coreblazor-server-sidedynamic-html

Blazor pages: how to use BuildRenderTree to add dynamic content


Background: We run dozens of sites for clients; all use an identical code base (ASP.NET WebForms) but completely different designs. Page structure is generated programmatically from SQL Server meta-data, using controls such as Panel, which are added to the ASP.NET page's Controls collection, and become DIVs in the rendered HTML.

Objective: We want to migrate eventually to ASP.NET CORE. However, there seems to be no equivalent to the page's controls collection. The closest thing I can find is the RenderTreeBuilder to add a Blazor component.

Question: Is it possible use BuildRenderTree to add a component which contains our home-baked HTML (for instance, to contain everything between <body> and </body>?

I've read articles such as:

https://chrissainty.com/building-components-via-rendertreebuilder/

https://learn.microsoft.com/en-us/aspnet/core/blazor/components?view=aspnetcore-3.1#manual-rendertreebuilder-logic

... and experimented with adding HTML elements, but it's extremely cumbersome, and I'd like to programmatically generate the HTML for pretty much the whole page, and add it as one RenderFragment (is that the right term?).

Is this possible? Is there an alternative?

Edit:


@Henk's answer, using the MarkupString struct, and mine, using RenderTreeBuilder.AddMarkupContent seem similar in terms of effort and plumbing required.

Are there any pros and cons of the two approaches I should consider?


Solution

  • I hadn't come across the MarkupString struct, so @Henk's answer is really helpful. I've now also come across the RenderTreeBuilder.AddMarkupContent method, so I'll offer this as an alternate answer:

    My markup:

    @page "/"
    <PageBuilder></PageBuilder>
    

    PageBuilder is a class that inherits from ComponentBase:

    public class PageBuilder : ComponentBase
    {
        protected override void BuildRenderTree(RenderTreeBuilder b)
        {
            base.BuildRenderTree(b);
            b.OpenElement(0, "div");
            b.AddMarkupContent(1, TheContent());
            b.CloseElement();
        }
        public string TheContent()
        {
            return "<div>This is the generated content</div>";
        }
    

    I'll edit my original question a little, as I'd like to know whether there's anything to choose between this approach and @Henk's.