
Dynamically rendering Blazor components by extending the Microsoft.AspNetCore.Components.ComponentBase class
Blazor is a rewarding framework to work with because it is mature enough to be useful and flexible and young enough to be shaped by its open-source community (and feature requests). Most of all, it is supported generously on Stack Overflow and within the ASP.NET Core GitHub site.
Most exciting of all, the usefulness of the Blazor framework increases exponentially, when Blazor components can be created dynamically. How can this be done?
Note that generalizations and customizations to Blazor components are hot topics that have enjoyed many recent enhancements (at the time of writing), including
- Templating
- Using ExpandoObject parameters
- Defining the Blazor component as a child class of the Microsoft.AspNetCore.Components.ComponentBase class and overriding the BuildRenderTree function.
- Using DynamicComponent (described in this article, authored as recently as March 2022)
While it is easy to find trivial examples of all that ASP.NET Core and Blazor can do, the deep dive of working with complex examples, can truly test the limits of the medium one is working with and convey a feeling for what is happening in the invisible realms of memory.
In this blog, I would like to document a few gems of Blazor knowldege that I picked up while working through the third of the approaches listed above.
Sequence Numbers
While dynamically assigning (i.e. not hard-coding) sequence numbers is strongly discouraged, this is an example of a rule that should be applied in the correct scenerios.
When dynamically rendering a complex component, you will find yourself writing loops within recursive code (if you don’t think so, then I would like to see your code). In other words, you will be (rightfully) reusing your code, for instance to render tab contents (that conceptually resemble sibling elements). With hard-coded sequence numbers, the Blazor framework thinks that we are rewriting the same element (e.g. the same tab contents), so rather than replacing the tab contents on the page, it will append to the already visible tab contents. This is the most obvious side-effect, easily worked around by dynamically assigning sequence numbers to mimic a pre-defined list of siblings (as one would have when using markup on a razor page).
Delegates and Lambdas
Another gem, is first-hand experience with the memory management behind lambda calls. RenderFragments are delegates that are defined using lambdas. When building the RenderFragments, variables are passed into the lambda body by reference and are modified by the lambda, but you sometimes cannot predict when they will be accessed and modified. For instance, in the case of a tabstrip component, the Blazor framework does not invoke the RenderFragment of the tabcontents until the moment of rendering it. By that time, the referenced variables may have been squashed by code meant to clean up after the tabstrip component itself. The workaround is to copy the needed values explicitly and at the correct moment.
Conclusion
In this blog, I have covered two gotchas (and insights) that I have discovered by taking ASP.NET MVC to the next level with .NET Core and dynamically rendered complex Blazor components. Whenever possible, let your creativity run free, test the limits of your medium, engage in the mental gymnastics needed, and come out with a thorough understanding of the nuts and bolts that you are working with. Take joy from the craft.