realm / realm-dotnet

Realm is a mobile database: a replacement for SQLite & ORMs
https://realm.io
Apache License 2.0
1.26k stars 165 forks source link

Realm change event & synchronization context #1841

Closed pfedotovsky closed 4 years ago

pfedotovsky commented 5 years ago

Goals

Get notifications when Realm is changed on the server (related issue https://github.com/realm/realm-dotnet/issues/1840)

I'm having hard time to undestand how to get notifications to work. The https://realm.io/docs/dotnet/latest/#notifications says that synchronization context must be installed (i.e. for Android). I've set up Nito.AsyncEx (see code below), but it isn't working. I haven't managed to find any code examples, it would be nice to see working sample.

Expected Results

RealmChanged event is triggered when Realm is changed

Actual Results

RealmChanged event is not triggered when Realm is changed

Steps to Reproduce

  1. Create new instance in Realm cloud
  2. Create new Realm
  3. Create class and populate it with some data
  4. Implement client that listens to RealmChanged event
  5. Change value in Realm Studio (or via C# client)

Code Sample

If I change FirstName in cloud realm, RealmChanged event is not triggered

        public static void Main()
        {
            AsyncContext.Run(async () => await Loop());
            Console.ReadLine();
        }

        public static async Task Loop()
        {
            // get user info & realm URL

            var syncConfiguration = new FullSyncConfiguration(realmUrl, user);

            Console.WriteLine(SynchronizationContext.Current);

            var realm = Realm.GetInstance(syncConfiguration);

            realm.RealmChanged += (s, e) =>
            {
                Console.WriteLine("Realm has changed");
            };    
        }

Version of Realm and Tooling

t-knapp commented 4 years ago

Same here. It seems Realm.RealmChanged in not invoked.

fealebenpae commented 4 years ago

Nito.AsyncEx's AsyncContext maintains its SynchronizationContext for as long as the delegate passed to AsyncContext.Run executes. In the example above the context ends immediately after subscribing to the Realm.Changed event, so any notifications coming in aren't delivered because the SynchronizationContext the realm instance was opened on no longer loops.

The simplest fix is to call SynchronizationContext.Current.OperationStarted() as the last thing inside the AsyncContext.Run delegate to prevent the context from exiting. When you need the context to exit call the OperationCompleted() method.

In short, make sure to prolong the life of the AsyncContext for as long as you need your realm objects to deliver notifications.