Laurence73
Laurence73

Reputation: 1327

What is the recommended way to release the UI from a long running background task in Blazor client-side

Our Blazor (client-side) app is made up of many components all existing on the UI at the same time. One of these has to do a number of large data calls to Azure SQL. This component does these calls regardless of whether it has UI focus or not. Each of calls these can take up to 3 seconds to return its result during which it renders the UI unresponsive. How can we keep the UI responsive during these calls without using Blazor server-side. Using Task.Run etc does not help in single threaded architecture. Using loading spinners is also not an option as this still leaves the UI unresponsive and may not be visible to the user. Is there any way to achieve this goal in current Blazor 0.9.0?

Running latest Blazor preview release (0.9.0-preview3-19154-02)

Upvotes: 7

Views: 5836

Answers (4)

Allie
Allie

Reputation: 1179

the suggested answer did not work, for me, I ended up using :

 protected override void OnInitialized()
 {
    InvokeAsync(async () =>
    {
        myvar = await YourCodeHere();
        StateHasChanged();

    });
    base.OnInitialized();
}

public async Task<MyVarType> YourCodeHere()
{
    ...
} 

Explanation: I have a class called MyVarType that I am using to display values on the Razor component. I have a myVar variable instantiated with that class, and initially it is empty. The component will render its default values immediately. Upon initializing the variable is then also being asynchronously assigned from the OnInitialized method. The YourCodeHere function could take several seconds. The Razor component rerenders when calling StateHasChanged() so it displays the loaded values.

Upvotes: -1

feyd
feyd

Reputation: 305

I've had success with Task().Start()

put your work in an async Task like so:

async Task MyWork()
{
    //sleep 10000
}

now from wherever you don't want this work to block call:

new Task( () => MyWork()).Start() );

I've only used this with Blazor Server, so haven't tested it with Client side Blazor which I hear can have different results because of its running on a single thread.

Upvotes: 0

dani herrera
dani herrera

Reputation: 51655

You can use Invoke, I modified counter example page to illustrate it, you will need a kind of singleton DI object to avoid running the process for twice.

Remember Blazor is an experimental project. Also, this answer is also an experimental approach.

@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" onclick="@IncrementCount">Click me</button>

@functions {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }

    protected  override void OnInit()
    {
        Invoke(
            //here your task.
            async () =>
            {
                for(var i =0; i< 50; i++)
                {
                    await Task.Delay(1000);
                    currentCount++;
                    StateHasChanged();                    
                    System.Console.WriteLine("Still running ...");
                }
            });
    }
}

Upvotes: 2

Vakhtangi Abashidze
Vakhtangi Abashidze

Reputation: 112

If async calls does not help then you can use browser workers, just need to implement some js interop.

Upvotes: 1

Related Questions