Search code examples
asp.net-coreblazorblazor-webassembly

How does cascaded parameter Task<AthenticationState> get unwrapped and exposed as "context" in AuthorizeView and AuthorizedRouteView in Blazor WASM?


There is a an object of type AuthenticationState named "context" that is available inside AuthorizeView and AuthorizedRouteView components. This object allows to access the ClaimsPrincipal via context.User.

I can see in the source code that AuthenticationState is passed down to these components as Task by the CascadingValue component implemented in the CascadingAuthenticationState component (which in turn is defined at the top of the component hierarchy in App.razor).

However, when I inspect the source of the AuthorizeRouteView I can see the cascading parameter of type Task named ExistingCascadedAuthenticationState. Yet, it is a complete mystery to me how and where does the Task gets unwrapped and exposed as "context". Does anyone know the answer?


Solution

  • You need to dig deep, and it's a little complicated.

    1. AuthorizeView inherits from AuthorizeViewCore
    2. AuthorizedRouteView builds it's own AuthorizeRouteViewCore inheriting from AuthorizeViewCore.

    Code at the bottom of AuthorizedRouteView:

    private sealed class AuthorizeRouteViewCore : AuthorizeViewCore
    {
        [Parameter]
        public RouteData RouteData { get; set; } = default!;
    
        protected override IAuthorizeData[]? GetAuthorizeData()
          => AttributeAuthorizeDataCache.GetAuthorizeDataForType(RouteData.PageType);
    }
    

    AuthorizedRouteView captures any cascade into ExistingCascadedAuthenticationState. If one exists (not null) then CascadingAuthenticationState exists in App, so nothing more needs doing. If it's null then it adds CascadingAuthenticationState as the component root component into its render fragment. This guarantees that Task<AuthenticationState> is cascaded.

    AuthorizeViewCore captures the cascaded value:

    [CascadingParameter] private Task<AuthenticationState>? AuthenticationState { get; set; }
    

    It gets "unwrapped" in OnParametersSetAsync

    currentAuthenticationState = await AuthenticationState;
    isAuthorized = await IsAuthorizedAsync(currentAuthenticationState.User);
    

    and used in BuildRenderTree to the "context" you see.

    var authorized = Authorized ?? ChildContent;
    builder.AddContent(0, authorized?.Invoke(currentAuthenticationState!));
    

    The content comes from:

    RenderFragment<TValue>
    

    declared as follows where TValue- content - is declared as AuthenticationState :

    [Parameter] public RenderFragment<AuthenticationState>? Authorized { get; set; }