Configure & Open a Synced Realm - .NET SDK
On this page
Synced Realms
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 vs. Non-Synced Realms
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.
Convert Between Synced and Non-Synced Realms
To convert a non-synced realm to a synced realm, you can follow the process described in Migrate a Local-Only App to a Sync-Enabled App. The .NET SDK also provides the WriteCopy() method, which enables you to duplicate a non-synced realm's data to a sync realm. For more information, refer to Migrate from Non-Synced Realms to Synced Realms.
Note
Partition-Based Sync Only
This method only supports converting between a non-sync realm and Partition-Based Sync. If your app uses Flexible Sync, you must manually iterate through the objects in one realm and copy them into the other realm.
Synced Realms
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.
Open a Synced Realm
The typical flow for opening a synced realm involves:
Creating a sync configuration.
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.
Open a Synced Realm While Online
The steps for opening a synced realm while online are:
Your app code walks the user through authenticating.
Create a FlexibleSyncConfiguration object that includes User object.
Open a synced realm by calling the GetInstanceAsync() method.
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);
Open a Synced Realm While Offline
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 }
Configuring Timeouts with AppConfiguration
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 messagePongKeepAliveTimeout
: 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), }, };
Scoping the Realm
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()
.
Class Subsets
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) } };