Home > Blockchain >  Blazor WASM Load Data before Render Page
Blazor WASM Load Data before Render Page

Time:02-14

I would like to load some Data before I Render my Blazor Application because in depndency to the loaded data I would like to render my app (layout, navbar ...)

Now I want to use the OnInitialised method instead of OnInitialisedAsync and with no async and await keywords.

But now I had a problem to convert the data which I get back from my API.

enter image description here

protected override void OnInitialized()
    {
        try
        {   Console.WriteLine("Test1Mainasync");
            LoadCategories();
        }
        catch (Exception e)
        {

            jsRuntime.ToastrError(e.Message);
        }
    }

    private void LoadCategories()
    {
        
       
        IEnumerable<CategorieDTO> CategoriesInit1  = new List<CategorieDTO>();
        CategoriesInit1  =  categorieService.GetAllCategories();
        
        SD.Categories = CategoriesInit1.ToList();
        //foreach(var categorie in CategoriesInit){
        //    SD.Categories.Append(categorie);
        //}
        
        Console.WriteLine("Test1Main");


    }

Has someone an idea why this converting issues happen?

CodePudding user response:

I think you have this method:

public async Task<IEnumerable<CategorieDTO>> GetAllCategories()

and you should call it this way:

private async Task LoadCategories()
{ 
    IEnumerable<CategorieDTO> CategoriesInit1  = new List<CategorieDTO>();
    CategoriesInit1  = await  categorieService.GetAllCategories();
    

and:

protected override async Task OnInitializedAsync()
{
    try
    {   Console.WriteLine("Test1Mainasync");
        await LoadCategories();
    }

CodePudding user response:

Your call to API endpoint return an awaitable task but not the IEnumerable, So you can not assign awaitable task to IEnumerable so this piece of code wont work

private void LoadCategories()
    {       
        IEnumerable<CategorieDTO> CategoriesInit1  = new List<CategorieDTO>();
        CategoriesInit1  =  categorieService.GetAllCategories();
}

You should have your LoadCategories function like this

private async Task LoadCategories()
{ 
    IEnumerable<CategorieDTO> CategoriesInit1  = new List<CategorieDTO>();
    CategoriesInit1  = await categorieService.GetAllCategories();
}

API calls should be awaitable, else it will stuck your UI

You can use this solution as well

private void LoadCategories()
    {      
       var t = Task.Run(() => categorieService.GetAllCategories()()).GetAwaiter();
        t.OnCompleted(() =>
        {
            CategoriesInit1 = t.GetResult();

            //  you may need to call statehaschanged as well
            StateHasChanged();
        });
}

CodePudding user response:

Has someone an idea why this converting issues happen?

In your code CatagiesInit1 is a Task, it's not a List<CategorieDTO>. You only get the List<CategorieDTO> when the task completes which you have no control over as you don't await the completion of the Task. In all likelyhood, your sync code will run to completion before that happens.

If your CategoryService returns a Task then the code that handles it must be async code. You can't escape from the async world back into the sync world without consequencies. If you want to live in the sync world then all the data pipeline code also needs to be blocking sync code.

If I understand your comments correctly, you want nothing to render until a certain set of conditions are met. If so add some standard Loading... component code to the page if it's page specific or App.razor if it's on initial load, or say MainLayout if it's application wide.

Here's a quick an dirty example:

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        @if (Loaded)
        {
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
        }
        else
        {
            <div >
                <h3>Loading.....</h3>
            </div>
        }
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

@code {
    private bool Loaded; 

    protected override async Task OnInitializedAsync()
    {
        Loaded = false;
        // simulate getting the data first
        await Task.Delay(5000);
        Loaded = true;
    }
}
  • Related