.NET Subscription notifications


#1

I am using the C# .NET code to perform a query based subscription on a Realm. It would appear though that the notifications are not firing. The PropertyChanged event is not firing. It also appears that the State property is always Creating.

I am following the documentation:
https://docs.realm.io/sync/using-synced-realms/syncing-data

var subscription = realm.All().Where(p => p.Age > 18).Subscribe();

// The Subscription class implements INotifyPropertyChanged so you can
// pass it directly to the data-binding engine
subscription.PropertyChanged += (s, e) =>
{
switch (subscription.State)
{
case SubscriptionState.Creating:
// The subscription has not yet been written to the Realm
break;
case SubscriptionState.Pending:
// The subscription has been written to the Realm and is waiting
// to be processed by the server
break;
case SubscriptionState.Complete:
// The subscription has been processed by the server and all objects
// matching the query are in the local Realm
break;
case SubscriptionState.Invalidated:
// The subscription has been removed
break;
case SubscriptionState.Error:
// An error occurred while processing the subscription
var error = subscription.Error;
break;
}
};

subscription.Results.AsRealmCollection().CollectionChanged += (s, e) =>
{
// Called whenever the objects in the local Realm which match the query
// change, including when a subscription being added or removed changes
// which objects are included.
};


#2

What platform are you running that on?


#3

Platform: Windows 10.


#4

Okay, what project is this? UWP/.NET Core? Are you subscribing from a thread that has a synchronization context?


#5

This is a .NET microservice using the Realm NuGet package for .NET Standard version 3.4.0. I am using the .NET code to write and update data into the remote Realm DB - where multiple mobile devices will be able to perform query based syncs.

There is no UI thread (as this is a background microservice) and no threads have a synchronization context. I think this is most likely to be the problem?


#6

That is correct - the fact there’s no synchronization context means that the Realm can’t refresh itself automatically - that’s explained briefly in the docs. You have two options - one is to install a synchronization context on the threads where you’re using Realm - that could be done with the Nito.AsyncEx package - it has an extremely simple API and is generally the recommended approach. The other is to periodically call realm.Refresh(). The problem with the second approach is that you have to make sure not to do any async work on the thread on which the Realm is opened, because the continuation will be dispatched on a random thread, thus breaking the requirement that a Realm is always accessed from the same thread. If you use Nito.AsyncEx, just wrap the entire method in AsyncContext.Run:

public void MyRealmAccessingMethod()
{
    AsyncContext.Run(async () =>
    {
        using (var realm = await Realm.GetInstanceAsync(someConfig))
        {
            var subscription = realm.All<Person>().Where(p => p.Age > 18).Subscribe();
            await subscription.WaitForSynchronizationAsync();
            // Do stuff
        }
    });
}

#7

Many thanks.

I am using the Nito.AsyncEx package and when I run the code above the subscription.State property does now change to complete. However, I am getting the following exception: “Access to invalidated Results objects”.


#8

Are you by any chance passing the results outside of the Nito.AsyncEx lambda scope?


#9

No. The code is nearly identical to that of your previous post. The Realm and query differs. That is all.

AsyncContext.Run(async() =>
{
    using (var realm = await Realm.GetInstanceAsync(realmConfiguration))
    {
        var subscription = realm.All<Message>().Subscribe();
        await subscription.WaitForSynchronizationAsync();

        logger.LogInformation("Synchronized realm.");
     }
});

#10

The exception is not thrown if the “using” statement is removed.

I think this could be related to this post: https://stackoverflow.com/questions/52811631/realm-js-access-to-invalidated-results-objects


#11

Which line throws this exception?


#12

The exception is thrown on the line of the closing parenthesis: });

AsyncContext.Run(async() =>
{
   using (var realm = await Realm.GetInstanceAsync(realmConfiguration))
   {
      var subscription = realm.All<Message>().Subscribe();
      await subscription.WaitForSynchronizationAsync();

      logger.LogInformation("Synchronized realm.");
   }
});  NOTE: The exception is thrown here!!!!!!

The code otherwise runs ok.

Like I said if the using statement is removed the exception is not thrown. i.e.

AsyncContext.Run(async() =>
{
   //using (var realm = await Realm.GetInstanceAsync(realmConfiguration))
   var realm = await Realm.GetInstanceAsync(realmConfiguration);
   {
      var subscription = realm.All<Message>().Subscribe();
      await subscription.WaitForSynchronizationAsync();

      logger.LogInformation("Synchronized realm.");
   }
});

I think is is something to do with Dispose() being called on the Realm?