How it works

The render pipeline end-to-end.


How it works

Conceptually, MapRazorComponentEndpoints():

  1. Scans the target assembly for IComponent types with a RouteAttribute.
  2. For each route, registers a MapMethods(["GET", "POST"], …) endpoint.
  3. The endpoint:
    • Builds a parameter dictionary from HttpContext (route values, form, query) and the component's [Parameter] properties.
    • Calls ComponentRenderer.RenderAsync(httpContext, componentType, parameters).
  4. ComponentRenderer composes the render tree, outside-in:
    • <CascadingValue HttpContext>
    • <CascadingValue Task<AuthenticationState>> (sourced from HttpContext.User)
    • Optional layout wrapper (LayoutAttribute)
    • The page component
  5. Renders the tree with Microsoft's HtmlRenderer (the same static renderer Blazor SSR uses), returns the resulting HTML string.

NavigationManager.NavigateTo throws NavigationException, caught by the endpoint and converted to a 302 (or 204 + HX-Redirect for htmx requests).

A component with [NotFoundPage] is registered as MapFallback, responding with status 404.

Why an internal RootRenderer?

HtmlRenderer.RenderComponentAsync(Type, ParameterView) takes a Type — but the render tree we want is a composed RenderFragment (cascading values wrapping an optional layout wrapping the page). The library defines an internal RootRenderer : ComponentBase whose only job is to emit a [Parameter] RenderFragment Content into the render tree. We pass that as the root and stuff the composed fragment in.

It's a five-line shim that exists purely to bridge "Blazor renders types" with "we want to render a fragment we built."

Why AddAuthorization() (not AddAuthorizationCore())?

<AuthorizeView> injects IAuthorizationPolicyProvider even when no Policy= is set. AddAuthorizationCore() registers that provider — but it also triggers WebApplication's auto-UseAuthorization() middleware, which then demands the AuthorizationPolicyMarkerService that only the full AddAuthorization() adds. So the library calls the full one.

What the auth cascade looks like

internal sealed class HttpContextAuthenticationStateProvider : AuthenticationStateProvider
{
    private readonly IHttpContextAccessor _accessor;
    public override Task<AuthenticationState> GetAuthenticationStateAsync()
        => Task.FromResult(new AuthenticationState(_accessor.HttpContext?.User ?? Anonymous));
}

Whatever ASP.NET Core's auth middleware put on HttpContext.User is what <AuthorizeView> sees. Wire up cookies/JWT/Windows auth the way you normally would; the library doesn't care.