Skip to content

Support prerendering closed generic components #27579

@javiercn

Description

@javiercn

Summary

We don't support rendering generic components as root components due to limitations in the way we serialize the type definition for the component (a similar thing happens for component parameters). We should consider lifting this limitation to support some more advanced scenarios.

Motivation and goals

Turns out that rendering generic components is useful if you want to write a "functional" component to wrap around another component, an example of this is when you are rendering multiple components at different points on a page and you want to, for example, require authentication for those components.

At that point, application developers are forced to write an individual wrapper for each of those components they want to wrap.

In scope

Support rendering closed generic components from Blazor applications.

Out of scope

TBD

Risks / unknowns

None so far

Examples

<CascadingAuthenticationState>
    <AuthorizeView>
        <Authorized>
            <TComponent @attributes="Params" />
        </Authorized>
    </AuthorizeView>
</CascadingAuthenticationState>

@code{
    [Parameter(CaptureUnmatchedValues = true)] public IDictionary<string,object> Params { get; set; }
}

Having a language syntax for writing these types of components is also desirable, otherwise it's cumbersome and likely error prone to author them:

    public class ProtectedWidget<T> : IComponent where T : IComponent
    {
        private RenderHandle _handle;
        private ParameterView _parameters;
        static RenderFragment _authorizeFragment;

        public ProtectedWidget()
        {
            _authorizeFragment = new RenderFragment(AuthorizedFragment);
        }

        public void Attach(RenderHandle renderHandle)
        {
            _handle = renderHandle;
        }

        public Task SetParametersAsync(ParameterView parameters)
        {
            _parameters = parameters;
            _handle.Render(BuildRenderTree);

            return Task.CompletedTask;
        }

        private void BuildRenderTree(RenderTreeBuilder builder)
        {

            builder.OpenComponent<CascadingAuthenticationState>(0);
            builder.OpenComponent<AuthorizeView>(1);
            builder.AddAttribute(1, "Authorized", _authorizeFragment);
            builder.CloseComponent();
            builder.CloseComponent();

        }
        void AuthorizedFragment(RenderTreeBuilder child)
        {
            child.OpenComponent<T>(0);
            child.AddMultipleAttributes(1, _parameters.ToDictionary());
            child.CloseComponent();
        }
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    affected-mediumThis issue impacts approximately half of our customersarea-blazorIncludes: Blazor, Razor Componentsdesign-proposalThis issue represents a design proposal for a different issue, linked in the descriptionenhancementThis issue represents an ask for new feature or an enhancement to an existing onefeature-prerenderingIssues related to prerendering blazor componentsseverity-minorThis label is used by an internal tool

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions