-
Notifications
You must be signed in to change notification settings - Fork 10.3k
API review: RazorComponentResult #47096
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The |
Curious how things like Blazor authorization compose with the minimal API world here. Does it all "just work" using the existing Blazor AuthN/Z primitives thanks to DI or does more stuff need to be flowed here? |
I'm not sure we want the existing blazor primitives to light up here. Do we want to run authorization multiple times? |
Well Blazor absolutely still needs its own level of authorization so that individual components can show different content to different users based on AuthZ policy. Anything applied at the endpoint level would be binary (i.e. can the user hit this endpoint or not) but after that AuthZ still needs to be available (similar to custom logic in an MVC action to return different results to different users for the same resource/endpoint). |
The existing |
Good point - will be sure to include that in the API review follow-up actions. |
API Review Notes:
API Approved! namespace Microsoft.AspNetCore.Http.HttpResults
{
public class RazorComponentResult<TComponent> : RazorComponentResult where TComponent: IComponent
{
public RazorComponentResult() {}
// NOTE: We should make sure you get proper trimmer warnings on this overload
public RazorComponentResult(object parameters) {}
public RazorComponentResult(IReadOnlyDictionary<string, object?> parameters) {}
}
public class RazorComponentResult : IResult, IStatusCodeHttpResult, IContentTypeHttpResult
{
public RazorComponentResult(Type componentType) {}
public RazorComponentResult(Type componentType, object parameters) {}
public RazorComponentResult(Type componentType, IReadOnlyDictionary<string, object?> parameters) {}
public Type ComponentType { get; }
public IReadOnlyDictionary<string, object?> Parameters { get; }
public string? ContentType { get; set; }
public int? StatusCode { get; set; }
public bool PreventStreamingRendering { get; set; }
public Task ExecuteAsync(HttpContext httpContext) {}
}
} |
That ctor can be marked as unsafe for trimming/AOT, and people can use the dictionary alternative. That pattern works elsewhere (e.g. Do we want to continue to encourage that pattern? IDK. I'll leave that decision up to Steve/Razor team. This issue was created a while ago, before we started supporting AOT in .NET 8, so thinking about whether it is ok to introduce new APIs that are unsafe may have changed in the Razor team. |
Should all now be implemented in #50181 |
I use a lot, minimalapi route/endpoint for blazor the question in my case .net8 prev7, RazorComponentResult |
Background and Motivation
As part of the Blazor United work, allows developers to render a Razor Component from an MVC action or minimal endpoint.
Proposed API
Result:
Result executor, which is registered in DI as singleton by default:
Usage Examples
We may later add helper methods for creating these without having to
new
them manually. That is tracked by #47094. However it would also be possible to construct them manually:Minimal:
MVC:
Alternative Designs
We considered a few different ways to support passing parameters to the component, including:
A. As a
ParameterView
B. As an anonymously-typed object (like the existing
Html.RenderComponentAsync
helper or<component>
tag helper does)C. As an
IReadOnlyDictionary<string, object>
(like the existingHtml.RenderComponentAsync
helper or<component>
tag helper does)D. By actually instantiating the component instance yourself and setting its parameter properties directly
Of these, the ones supported in this PR are B and C, and in both cases it will coerce the value you give to an
IReadOnlyDictionary<string, object>
because (1) we have to do that anyway, as it's a step on the route to coercing it to aParameterView
which the component actually needs, and (2) having it as a dictionary makes it easy for customers' unit tests to read back the contents ofParameters
to make assertions about what their MVC actions are doing.I haven't put in support for passing a
ParameterView
directly because it's unlikely anybody would find that convenient. But we could easily add that constructor overload if we wanted.I haven't put in support for option D, because it would violate the normal component lifecycle by bypassing the
SetParametersAsync
method. Most components would still work fine in practice, but some legitimately-authored components could fail to work if their parameters were not set viaSetParametersAsync
. If we were determined to do D, it would probably have to be achieved by using reflection to discover the[Parameter]
properties, reading back the values you set, resetting them back to defaults, then preparing aParameterView
that contains the values to be assigned viaSetParametersAsync
. That's not super lovely because it relies on reflection, and it's always possible that custom getters/setters on the parameter properties would throw if you do something unexpected like explicitly write a null value to them.Risks
Nothing specific. This is the most basic and obvious way to achieve some functionality we know we want.
The text was updated successfully, but these errors were encountered: