Home > other >  How does cascaded parameter Task<AthenticationState> get unwrapped and exposed as "contex
How does cascaded parameter Task<AthenticationState> get unwrapped and exposed as "contex

Time:10-18

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?

CodePudding user response:

The comment of enet helped me to find the answer.

When we have a RenderFragment<TValue> delegate, the <TValue> is exposed by default as @context.

For example, in AuthorizeRouteView we have a parameter NotAuthorized:

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

In this case AuthenticationState is TValue, therefore AuthenticationState is exposed as @context.

This article on Blazor University was the key for me to get the concept: Passing placeholders to RenderFragments.

CodePudding user response:

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:

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

CodePudding user response:

The cascading parameter is Task<AuthenticationState> context Which tells you that context, when awaited, will return the object of type AuthenticationState. So what you get is a Task. The task when awaited, returns the value returned by the Task. The actual syntax for accessing the User is

var state = await context;
var user = state.User;

Also, you can give any name to the cascading parameter. So

[CascadingParameter]
public Task<AuthenticationState> AuthState {get;set;}

var state = await AuthState;
var user = state.User;

is equally valid.

  • Related