dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.15k stars 9.92k forks source link

Support prerendering closed generic components #27579

Open javiercn opened 3 years ago

javiercn commented 3 years ago

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();
        }
    }
ghost commented 3 years ago

Thanks for contacting us. We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

ghost commented 3 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost commented 9 months ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.