Docs Menu

Docs HomeAtlas Device SDK

Configure & Open a Synced Realm - .NET SDK

On this page

  • Synced Realms
  • Synced Realms vs. Non-Synced Realms
  • Convert Between Synced and Non-Synced Realms
  • Synced Realms
  • Open a Synced Realm
  • Open a Synced Realm While Online
  • Open a Synced Realm While Offline
  • Configuring Timeouts with AppConfiguration
  • Scoping the Realm
  • Class Subsets

You can configure a realm to automatically synchronize data between many devices that each have their own local copy of the data. Synced realms use a different configuration than local-only realms and require an Atlas App Services backend to handle the synchronization process.

Applications can always create, modify, and delete synced realm objects locally, even when offline. Whenever a network connection is available, the Realm SDK opens a connection to an application server and syncs changes to and from other clients. The Atlas Device Sync protocol and server-side operational transforms guarantee that all fully synced instances of a realm see exactly the same data, even if some changes occurred offline and/or were received out of order.

Tip

Learn How to Configure and Use Sync

For more information on Device Sync, including directions on how to set up sync in an App Services app, see Sync Data Between Devices - .NET SDK.

Synced realms differ from non-synced local Realm in a couple of ways:

  • Synced realms attempt to sync changes with your backend App Services App, whereas non-synced realms do not.

  • Synced realms can be accessed by authenticated users, while non-synced realms have no concept of users or authentication.

You can copy data from a non-synced realm to a synced realm, and vice versa, but you cannot sync a non-synced realm.

Realm does not have a direct mechanism to add sync to a non-synced realm, or to permanently stop Sync for a synced realm. However, the .NET SDK does provide methods that enable you to copy a realm file for use with a different configuration. With these methods, you can easily duplicate a realm's data, which you can then open with a sync or non-sync configuration. This lets you indirectly add Sync to a non-synced realm, or permanently stop a realm from syncing. For more information, refer to Convert Between Non-Synced Realms and Synced Realms - .NET SDK.

To open a synced realm, you must have an authenticated User object. To obtain an initial User instance, you need to authenticate against the Atlas App Services backend, which requires the device to be online the first time a user logs in. Once initial authentication has occurred, you can retrieve an existing user while offline.

Note

The first time a user logs on to your app, you should open the realm asynchronously to sync data from the server to the device in a background thread. After that initial sync, you can open a realm synchronously to ensure the app works in an offline state.

The typical flow for opening a synced realm involves:

  1. Authenticating the user.

  2. Creating a sync configuration.

  3. Opening the user's synced realm with the configuration.

At authentication, we cache user credentials in a sync_metadata.realm file on device.

When you open a synced realm after authenticating, you can bypass the login flow and go directly to opening the synced realm, using the same sync configuration you already created.

With cached credentials, you can:

  • Open a synced realm immediately with the data that is on the device. You can use this method offline or online.

  • Open a synced realm after downloading changes from your App. This requires the user to have an active internet connection.

The steps for opening a synced realm while online are:

  1. Your app code walks the user through authenticating.

  2. Create a FlexibleSyncConfiguration object that includes User object.

  3. Open a synced realm by calling the GetInstanceAsync() method.

  4. If your FlexibleSyncConfiguration did not contain initial subscriptions, add a subscription.

The following code demonstrates these steps:

var app = App.Create("myRealmAppId");
var user = await app.LogInAsync(Credentials.Anonymous());
Realm realm;
var config = new FlexibleSyncConfiguration(user)
{
PopulateInitialSubscriptions = (realm) =>
{
var allTasks = realm.All<MyTask>();
realm.Subscriptions.Add(allTasks, new SubscriptionOptions { Name = "allTasks" });
}
};
try
{
realm = await Realm.GetInstanceAsync(config);
}
catch (Exception ex)
{
Console.WriteLine($@"Error creating or opening the
realm file. {ex.Message}");
}

In the above example, the code shows how to open the realm asynchronously by calling GetInstanceAsync(). You can also open a realm synchronously by calling the GetInstance() method:

var synchronousRealm = Realm.GetInstance(config);

Once a user authenticates, the User object persists on the device until the user logs off. This allows your app to retrieve an existing user and open a synced realm in an offline state. Changes that occur while offline will be synced by the SDK once the device reconnects to your App.

The following code shows how to check if there is an existing User object. If none is found, it uses the process outlined about to obtain a user. If the device already has a user, it opens the synced realm with that user:

var app = App.Create("myRealmAppId");
Realms.Sync.User user;
FlexibleSyncConfiguration config;
Realm realm;
if (app.CurrentUser == null)
{
// App must be online for user to authenticate
user = await app.LogInAsync(Credentials.Anonymous());
config = new FlexibleSyncConfiguration(user);
realm = Realm.GetInstance(config);
// Go on to add or update subscriptions and use the realm
}
else
{
// This works whether online or offline
// It requires a user to have been previously authenticated
user = app.CurrentUser;
config = new FlexibleSyncConfiguration(user);
realm = Realm.GetInstance(config);
// Go on to add or update subscriptions and use the realm
}

For granular control of your app connection, you can set the SyncTimeoutOptions on the AppConfiguration object. You can set the following Sync timeout properties:

  • ConnectTimeout: the amount of time to allow for a connection to become fully established.

  • ConnectionLingerTime: the amount of time to keep a connection open after all sessions have been abandoned.

  • PingKeepAlivePeriod: the amount of time between each heartbeat ping message

  • PongKeepAliveTimeout: the amount of time to wait for a response to a heartbeat ping before concluding that the connection has dropped.

  • FastReconnectLimit: the amount of time since the loss of a previous connection for a new connection to be considered a "fast reconnect".

AppConfiguration configuration = new AppConfiguration("myRealmAppId")
{
SyncTimeoutOptions = new SyncTimeoutOptions()
{
ConnectTimeout = TimeSpan.FromMinutes(2),
ConnectionLingerTime = TimeSpan.FromSeconds(30),
PingKeepAlivePeriod = TimeSpan.FromMinutes(1),
PongKeepAliveTimeout = TimeSpan.FromMinutes(1),
FastReconnectLimit = TimeSpan.FromMinutes(1),
},
};

The realm instance implements IDisposable to ensure native resources are freed up. You should dispose of a realm object immediately after use, especially on background threads. The simplest way to do this is by declaring the realm object with a using statement, or wrapping the code that interacts with a realm in a using (...) statement:

config = new PartitionSyncConfiguration("myPart", user);
using (var realm = Realm.GetInstance(config))
{
var allItems = realm.All<Item>();
}

If you require a realm object to be shared outside of a single method, be sure to manage its state by calling the Dispose() method:

realm.Dispose();

Note

As a general rule, you should dispose of the realm only on background threads, because disposing of a realm invalidates all objects associated with that instance. If you are data binding the realm objects on the main thread, for example, you should not call Dispose().

By default, all RealmObject classes are stored in a realm. In some scenarios, you may want to limit the classes that get stored, which you can do with the Schema property of the RealmConfiguration object. The following code demonstrates how you specify two classes you want stored in the realm:

var config = new RealmConfiguration()
{
Schema = new Type[]
{
typeof(AClassWorthStoring),
typeof(AnotherClassWorthStoring)
}
};
←  Add Device Sync to an App - .NET SDKWrite to a Synced Realm - .NET SDK →