Home > Net >  In Blazor what is the difference between `await Task.Run(StateHasChanged)` and `await InvokeAsync(St
In Blazor what is the difference between `await Task.Run(StateHasChanged)` and `await InvokeAsync(St

Time:11-30

I've recently inherited a Blazor Webassembly application, however have minimal experience with dotnet or Blazor.

Some of the components use await Task.Run(StateHasChanged) rather than await InvokeAsync(StateHasChanged) and I'm wondering if this is intentional.

I ask as await Task.Run(StateHasChanged); gives me the following exception when attempting to render the component using bUnit:

System.InvalidOperationException The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.

Changing this to await InvokeAsync(StateHasChanged); allows the component to be rendered in bUnit. However, as far as I can tell, the component functions identically when using the application for either await Task.Run(StateHasChanged) or await InvokeAsync(StateHasChanged).

What is the difference between these two approaches to invoking StateHasChanged?

CodePudding user response:

as far as I can tell, the component functions identically ...

That is correct. Task.Run(job) will run the job on the ThreadPool. In WebAssembly however there are no extra threads and the main (only) thread will have to run this job sooner or later.

In Blazor Server you do have Threads. Task.Run() will work there, but StateHasChanged() has to run on the main Thread. That means that

 await Task.Run(StateHasChanged)   // bug!  Don't do this.

definitely is a bug, everywhere. It just goes unnoticed on WebAssembly for the time being. Until the day that Blazor Wasm also gets threads, then it will throw.

So bUnit is right, fix your code.

Do note that in 'normal' lifecycle events (like OnInitialized[Async], OnClick, OnSubmit etc) you don't have to use InvokeAsync() at all. I normally use just

  StateHasChanged();

and in in external events (eg a Timer) or Threaded code (on the Server)

  await InvokeAsync(StateHasChanged);
  • Related