Blazor exception - The current thread is not associated with the Dispatcher. Use InvokeAsync()

Viewed 2054

I my Blazor application I have such exception

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.
   at Microsoft.AspNetCore.Components.Dispatcher.AssertAccess()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
   at Microsoft.AspNetCore.Components.ComponentBase.Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, Object arg)
   at Microsoft.AspNetCore.Components.EventCallback`1.InvokeAsync(TValue arg)
   at MyApplication.Web.Shared.Application.ApplicationBarService.SearchFromUri(NavigationManager navigationManager) in /app/src/MyApplication.Web/Shared/Application/ApplicationBarService.cs:line 132
   at MyApplication.Web.Shared.Application.ApplicationBar.OnAfterRenderAsync(Boolean firstRender) in /app/src/MyApplication.Web/Shared/Application/ApplicationBar.razor:line 367
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
2020-09-01 10:32:06.818 +00:00 [ERR] Unhandled exception in circuit 'b625BJVxR9Sa5e1W6l6unK0G7RAkkLuM3kbvMggpJV0'.
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.
   at Microsoft.AspNetCore.Components.Dispatcher.AssertAccess()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
   at Microsoft.AspNetCore.Components.ComponentBase.Microsoft.AspNetCore.Components.IHandleEvent.HandleEventAsync(EventCallbackWorkItem callback, Object arg)
   at Microsoft.AspNetCore.Components.EventCallback`1.InvokeAsync(TValue arg)
   at MyApplication.Web.Shared.Application.ApplicationBarService.SearchFromUri(NavigationManager navigationManager) in /app/src/MyApplication.Web/Shared/Application/ApplicationBarService.cs:line 132
   at MyApplication.Web.Shared.Application.ApplicationBar.OnAfterRenderAsync(Boolean firstRender) in /app/src/MyApplication.Web/Shared/Application/ApplicationBar.razor:line 367

It asks to use InvokeAsync, but I'm already into an "OnAfterRenderAsync"! So, why do I have such an issue?

In my situation, I have 3 elements

  • an ApplicationBarService (global to the app)
  • an ApplicationBarComponent.razor
  • a page Index.razor

What I suspect

The ApplicationBar component is inside the page Index.razor. It means that OnAfterRender is called on ApplicationBar first, then on Index.

So, here is the call stack / order:

  1. ApplicationBar.OnAfterRenderAsync ->
  2. ApplicationBarService.SearchFromUri -> (CALL DONE WITH AN EventCallback)
  3. Index.Search(...)

One problem is that Index.razor is not yet "ready" (no call to OnAfterRender has been done yet). There I cannot do any JS call :-(

Maybe I should do this call once all "parent" are ready, but how ?

Some code

It is a simple event

public EventCallback<SearchEventArgs> OnSearch;

I call it this way:

await OnSearch.InvokeAsync(args);

And the last code, On Index.razor I have:

public async Task Search(SearchArgs args)
{
 base.InvokeAsync( ... );
}

The last method is the one called by the event, there I also use base.InvokeAsync to insure I do the call in the right thread ! But even with this I have some issues, I cannot do JS calls because the OnAfterRender has not been called yet !

So, do you have any idea about the problem?

Also, I have to some change, just to be sure to call from the same components. If you look at the code:

  • I call from OnAfterRender, call a "static" class, then go back to the same component. Then this component try to do the last call.
  • In the last call I use InvokeAsync and EventCallback (This one should InvokeAsync too)

But even with this, it ask me to call InvokeAsync (But it is done) !!!

enter image description here

1 Answers

Without seeing all the code its hard to say for sure, but likely you need to surround a StateHasChanged like

InvokeAsync(() => StateHasChanged());

Blazor university has a nice in-depth explanation.

Related