最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

asp.net core - CascadingParameter is null problem in Blazor Server - Stack Overflow

programmeradmin3浏览0评论

I'm using Blazor Server on .NET 9, I have this components tree:

- <ShoppingCartState>
   - <ShoppingCartPage>
     - <ShoppingCartLayout>
        - <ShoppingCart>   route start here  @page/shopping-cart
          - <CartItems>

ShoppingCartState provides a CascadingValue called CartModel when I navigate to /shopping-cart page, the CartModel is always accessible in ShoppingCart component or after it, but not before it for example in ShoppingCartLayout it always null.

I'm confused and I don't know. I feel that because the page starts rendering from here, that parameter can be received from here. If this is the problem, what is the solution to receive it in the previous components?

ShoppingCartState code :

@inject IShoppingCartService CartService
@implements IDisposable
@rendermode InteractiveServer

<div class="">
    <Loader IsLoading="IsLoading||CartModel is null">
        @if (CartModel is not null)
        {
            <CascadingValue Value="OnCartUpdated">
                <CascadingValue Value="CartModel">
                    @ChildContent
                </CascadingValue>
            </CascadingValue>
        }
    </Loader>
</div>

@code {

    private bool IsLoading;

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    public Action OnCartUpdated { get; set; } = null!;

    public ShoppingCartModel? CartModel { get; set; } = new();

    protected override void OnInitialized()
    {
        OnCartUpdated += StateHasChanged;
    }

    public void Dispose()
    {
        OnCartUpdated -= StateHasChanged;
    }


    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await LoadCartAsync();
        }
    }

    private async Task LoadCartAsync()
    {
        IsLoading = true;
        CartModel = await CartService.GetCartAsync();
        IsLoading = false;
        StateHasChanged();
    }
}

I'm using Blazor Server on .NET 9, I have this components tree:

- <ShoppingCartState>
   - <ShoppingCartPage>
     - <ShoppingCartLayout>
        - <ShoppingCart>   route start here  @page/shopping-cart
          - <CartItems>

ShoppingCartState provides a CascadingValue called CartModel when I navigate to /shopping-cart page, the CartModel is always accessible in ShoppingCart component or after it, but not before it for example in ShoppingCartLayout it always null.

I'm confused and I don't know. I feel that because the page starts rendering from here, that parameter can be received from here. If this is the problem, what is the solution to receive it in the previous components?

ShoppingCartState code :

@inject IShoppingCartService CartService
@implements IDisposable
@rendermode InteractiveServer

<div class="">
    <Loader IsLoading="IsLoading||CartModel is null">
        @if (CartModel is not null)
        {
            <CascadingValue Value="OnCartUpdated">
                <CascadingValue Value="CartModel">
                    @ChildContent
                </CascadingValue>
            </CascadingValue>
        }
    </Loader>
</div>

@code {

    private bool IsLoading;

    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    public Action OnCartUpdated { get; set; } = null!;

    public ShoppingCartModel? CartModel { get; set; } = new();

    protected override void OnInitialized()
    {
        OnCartUpdated += StateHasChanged;
    }

    public void Dispose()
    {
        OnCartUpdated -= StateHasChanged;
    }


    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await LoadCartAsync();
        }
    }

    private async Task LoadCartAsync()
    {
        IsLoading = true;
        CartModel = await CartService.GetCartAsync();
        IsLoading = false;
        StateHasChanged();
    }
}

Share Improve this question edited yesterday jack asked yesterday jackjack 1091 silver badge9 bronze badges 1
  • When (and where) do you set the CartModel value? – Henk Holterman Commented yesterday
Add a comment  | 

3 Answers 3

Reset to default 0

It's not obvious from the code you've provided where the issue is. However, the ShoppingCartState code looks messy, doesn't need much of the logic you've coded, and is probably the cause the problem.

Some observations:

  1. Why are you getting CartModel in OnAfterRenderAsync instead of OnInitializedAsync? If you doing so to avoid trying to load CartModel in the pre-render, then use RendererInfo as I've shown in the code below. See - Is the NET 8 Blazor web app template flawed? and many other answers on why you shouldn't do what you're doing in OnAfterRenderAsync.

  2. [CascadingParameter] can be null, so deal with a possible null where your use it. The Loader stuff is an overcomplication you don't need.

Here's a simpler version of ShoppingCartState.

@inject IShoppingCartService CartService
@implements IDisposable
@rendermode InteractiveServer

<CascadingValue Value="OnCartUpdated">
    <CascadingValue Value="CartModel">
        @ChildContent
    </CascadingValue>
</CascadingValue>

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; }

    public Action OnCartUpdated { get; set; } = null!;

    public ShoppingCartModel? CartModel { get; set; } = new();

    protected override async Task OnInitializedAsync()
    {
      if (this.RendererInfo.IsInteractive)
      {
        CartModel = await CartService.GetCartAsync();
        OnCartUpdated += StateHasChanged;
      }
    }

    public void Dispose()
    {
        OnCartUpdated -= StateHasChanged;
    }
}

You could try put state in the the Routes.razor

<ShoppingCartState>
    <Router AppAssembly="typeof(Program).Assembly">
...
    </Router>
</ShoppingCartState>

By the way how do you wrap the components? what difference between <ShoppingCartPage> and <ShoppingCart>?

in all child components you need to add [CascadingParameter]. did you?

@code {
    [CascadingParameter]
    public ShoppingCartModel? CartModel { get; set; } = default!;
 
}

in child component it should not be new() and be default!

发布评论

评论列表(0)

  1. 暂无评论