ReactiveUI icon indicating copy to clipboard operation
ReactiveUI copied to clipboard

[BUG] RxApp.MainThreadScheduler wrong thread on Server-Side Blazor

Open bergi9 opened this issue 5 years ago • 7 comments

I tested DynamicData with Server-Side Blazor in combination with RxUI. The first Exceptions (System.InvalidOperationException: Collection was modified) came when ReadOnlyObservableCollection<> are accessed in the Blazor's renderer while DD updates the collections (with i.e.: observableChangeSet.observeOn(RxApp.MainThreadScheduler).Bind(out list)...). The RxApp.MainThreadScheduler obviously doesn't run on the same thread as Blazor's renderer. After some searching I found that the Dispatcher class exist in Microsoft.AspNetCore.Components.Dispatcher that's may used for the Blazor's renderer. An explicit scheduler implementation for server-side Blazor might missing?

bergi9 avatar Feb 07 '20 18:02 bergi9

Hey @bergi9 :wave:,

Thank you for opening an issue. We will get back to you as soon as we can. Also, check out our Open Collective and consider contributing financially.

https://opencollective.com/reactiveui

PS.: We offer priority support for all financial contributors. Don't forget to add priority label once you start contributing :smile:

An advanced, composable, functional reactive model-view-viewmodel framework for all .NET platforms!

The problem is blazor has a dispatcher per page and not a overall consistent thread for rendering. We might need to rethink rxapp static methods at some stage

glennawatson avatar Feb 07 '20 18:02 glennawatson

So the solution for now would be a ISchedulerProvider service registered as scoped service if I implement an IScheduler with the dispatcher's class? If then which base class for IScheduler should I take?

bergi9 avatar Feb 07 '20 18:02 bergi9

@bergi9

Can you provide an example illustrating the problem? I have a SPA project using DD as well and made some stress testing for the page rendering but I couldn't reproduce the synchronization problem. Maybe I have solved the StateHasChanged Invokation differently. Indeed using .ObserveOn(RxApp.MainThreadScheduler) doesn't make sense for Blazor yet.

b-straub avatar Apr 30 '20 10:04 b-straub

I think I may have encountered this issue.

The application works fine while debugging through VS 2019, Start Debug, but running the application with dotnet run fails to resolve a certain Observable.

jamescarter-le avatar May 07 '21 17:05 jamescarter-le

For anyone encountering this issue: Blazor Server and Blazor Hybrid provide a synchronization context that can be used to schedule UI updates on. So the following code is usually enough:

.ObserveOn(new SynchronizationContextScheduler(SynchronizationContext.Current))

This code captures the current Synchronization context, so it has to be executed within one of the overridden component lifecycle methods. However typically whenever you create / activate a viewmodel and define observables you are in a calltree that originated from one of the component lifecycle methods, so then it's safe.

If you are not just split the capture and usage of the synchronization context like this:


// capture the context on some render thread code:
var context = SynchronizationContext.Current;

//...

// use the context in some code that defines this observable outside the render thread:
.ObserveOn(new SynchronizationContextScheduler(context))

jspuij avatar Oct 09 '23 23:10 jspuij