Installation

On the “Packages” node under your project in the Solution pane, click the gear button and select “Add Packages…”

Type “Realm” in the search box

Select Realm and add it

You should see Fody added as a dependency in turn.

The Realm package contains everything you need to use Realm. It depends on Fody weaver, responsible for turning your RealmObject subclasses into persisted ones.

At this point, you should have the package installed. If your project was already using Fody you will see an update to your existing FodyWeavers.xml. The important thing is that you end up with a FodyWeavers.xml file that contains all the weavers you want active, including RealmWeaver.

This is an example of how your FodyWeavers.xml file should look if you were not already using any other weavers when you added Realm:

Check that your project is checked on the right hand side, so the Install button is enabled

Press Install

Press OK in the dialog that comes up, which should be telling you it will install Realm and Fody

The Realm package contains everything you need to use Realm. It depends on Fody weaver, responsible for turning your RealmObject subclasses into persisted ones.

At this point, you should have the package installed. If your project was already using Fody you will see an update to your existing FodyWeavers.xml. The important thing is that you end up with a FodyWeavers.xml file that contains all the weavers you want active, including RealmWeaver.

This is an example of how your FodyWeavers.xml file should look if you were not already using any other weavers when you added Realm:

Note for UWP, .NET Core and other .NET Standard projects: due to changes in NuGet 3.1, packages are no longer able to create content files, so FodyWeavers.xml will not be created automatically. You’ll need to manually create the file and paste the content above. Please refer to this post for more information.

Realm .NET enables you to efficiently write your app’s model layer in a safe, persisted, and fast way. Here’s what it looks like:

// Define your models like regular C# classes
publicclassDog:RealmObject{publicstringName{get;set;}publicintAge{get;set;}publicPersonOwner{get;set;}}publicclassPerson:RealmObject{publicstringName{get;set;}publicIList<Dog>Dogs{get;}}varrealm=Realm.GetInstance();// Use LINQ to query
varpuppies=realm.All<Dog>().Where(d=>d.Age<2);puppies.Count();// => 0 because no dogs have been added yet
// Update and persist objects with a thread-safe transaction
realm.Write(()=>{realm.Add(newDog{Name="Rex",Age=1});});// Queries are updated in realtime
puppies.Count();// => 1
// LINQ query syntax works as well
varoldDogs=fromdinrealm.All<Dog>()whered.Age>8selectd;// Query and update from any thread
newThread(()=>{varrealm2=Realm.GetInstance();vartheDog=realm2.All<Dog>().Where(d=>d.Age==1).First();realm2.Write(()=>theDog.Age=3);}).Start();

Getting Started

You install Realm via NuGet, or you can browse the source code on GitHub.

Prerequisites

We support the following platforms:

Xamarin.iOS for iOS 7 or later, using native UI or Xamarin Forms

Xamarin.Android for API level 10 or later, using native UI or Xamarin Forms

Xamarin.Mac for macOS 10.11 or later, using nativeUI or Xamarin Forms

.NET Framework 4.6.1 or later for Windows 8.1 or later

Universal Windows Platform applications using .NET Standard 1.4 or later

.NET Core 1.1 or later on:

Ubuntu 16.04 or later

Debian 8 or later

RHEL 7.1 or later

macOS 10.11 or later

Windows 10 or later

And the following environments:

Visual Studio 2015 Update 2 or higher

Visual Studio for Mac 7.0 or higher

Using .NET Core on Linux requires a token for the Professional or Enterprise Edition of the Realm Platform.

The dotnet command line tool is not supported when building for .NET Core. Please use Visual Studio or the msbuild command line tool to build your project.

Important note for PCL users: this works via the NuGet Bait and Switch Trick. You must install the Realm NuGet package into every PCL that uses Realm as well as each of your platform-specific projects, i.e., your final app for iOS and Android. If you are using shared projects, you only have to install the NuGet into each platform-specific project.

Android ABI Support

Due to some instruction set limitations, we do not support the armeabi ABI setting.

The default templates that create new Xamarin projects currently have all ABI settings checked, for Debug builds, but only armeabi on Release. You must change this before doing your own Release builds.

If you do not have other ABIs checked, a System.TypeInitializationException may occur when a user runs on a different device. For example, deploying on a 64-bit device such as a Galaxy Tab S2 will cause that error if you have armeabi and armeabi-v7a but notarm64-v8a checked.

Unless you have a good reason to avoid linking other ABIs, the best thing to do is to check all of them other than armeabi, so you want checked:

In Visual Studio on Windows, these settings are from right-clicking a project’s Properties - Android Options - Advanced Tab.

Realm Studio

Realm Studio is our premiere developer tool, built so you can easily manage the Realm Database and Realm Platform. With Realm Studio, you can open and edit local and synced Realms, and administer any Realm Object Server instance. It supports Mac, Windows and Linux.

Models

Realm model objects mostly function like any other C# objects – you can add your own methods and events to them and use them like you would any other object. The main restrictions are that you can only use an object on the thread which it was created, and persisted properties have generated getters and setters.

Also, note that your class must have a public, parameterless constructor. If you don’t add any constructors, the compiler will add this for you. However, if you add at least one constructor to your class, make sure there is a public parameterless one as well.

Relationships and nested data structures are modeled simply by including properties of the target type or IList for typed lists of objects.

Supported Types

Realm supports primitive types except unsigned ones (bool, char, byte, short, int, long, float and double) as well as string, and DateTimeOffset. The nullable equivalents are supported as well, described further in Optional Properties.

Collections

Using collections of supported objects is done by declaring a property of type IList<T> where T is any supported type:

Whilst you can specify a DateTimeOffset using a timezone, we store the UTC value. This is an unambiguous representation which will mean the same instant if read with other languages. However, because we lose the timezone specifier, this may cause confusion if you compare values using Ticks instead of UtcTicks.

Counters

Realm offers RealmInteger<T> as a special integer type. RealmInteger<T> exposes an additional API that can more clearly express intent and generate better conflict resolution steps when using Synchronized Realms. The type argument, T, can be either byte, short, int, or long.

Traditionally, a counter would be implemented by reading a value, incrementing it and setting it (myObject.Counter += 1). This will not work well in an asynchronous situation—for example when two clients are offline—because both parties will read a value, say 10, increment it, and store the value as 11. Eventually, when they regain connectivity and try to merge their changes, they’ll agree that the counter is at 11 rather than the expected 12.

RealmIntegers are backed by traditional integer types, so no migration is required when changing a property type from T to RealmInteger<T>.

Relationships

For lists, you declare classes with an IList property and an implementing object will be created when the getter is first used. You should only specify a get; automatic method as there is no way to set such a list.

To-One Relationships

For many-to-one or one-to-one relationships, simply declare a property with the type of your RealmObject subclass.

When using RealmObject properties, you can access nested properties using normal property syntax. For example rex.Owner.Address.Country will traverse the object graph and automatically fetch each object from Realm as needed.

To-Many Relationships

You can define a to-many relationship using IList properties. When you use these properties, you get back a collection which may be empty or contains related RealmObjects of a single type.

To add a “Dogs” property on our Person model that links to multiple dogs, we simply declare it as an IList<Dog> property. You don’t have to initialize the IList – the Realm SDK takes care of that for you. Just add and delete Dog objects from the list to establish the relationship between a given Person and a Dog.

Inverse Relationships

Links are unidirectional. So if a to-many property Person.Dogs links to a Dog instance and a to-one property Dog.Owner links to Person, these links are independent from one another. Appending a Dog to a Person instance’s Dogs property doesn’t automatically set the dog’s Owner property to this Person. Because manually synchronizing pairs of relationships is error prone, complex and duplicates information, Realm provides backlink properties to represent these inverse relationships.

With backlink properties, you can obtain all objects that link to a given object from a specific property. For example, a Dog object can have a property named Owners that contains all of the Person objects that have this exact Dog object in their Dogs property. This is done by making the Owners property of type IQueryable<Person> and then applying the [Backlink] attribute to indicate the relationship that Owners has with the Person model objects.

Optional Properties

Reference types such as string, byte[] and related RealmObject values can be null.

Nullable value types such as int? are fully supported.

We also support the optional DateTimeOffset? to complete the full range of having an optional version of each property type.

Controlling Property Persistence

Classes which descend from RealmObject are processed by the Fody weaver at compilation time. All their properties that have automatic setters and getters are presumed to be persistent and have setters and getters generated to map them to the internal Realm storage.

We also provide some C# attributes to add metadata to control persistence.

To avoid a property being made persistent, simply add the [Ignored] attribute. A common example is using external media, where you could persist the path to a file but not the binary image:

publicstringHeadshotPath{get;set;}// Image in memory during run
[Ignored]publicImageHeadshot{get;set;}

Custom Setters

Properties which have their own setter or getter implementation are automatically ignored. You can use this to add validation:

Mapped Properties

Realm files are inherently platform agnostic and can be opened or synchronized with any of the available bindings. To do that, the schema should be identical for different languages, including casing of property names. To avoid writing non-standard C# classes you can use the [MapTo] attribute, e.g.:

Auto-Updating Objects

As soon as an instance of a RealmObject is managed, it becomes a live, auto-updating views into the underlying data, which means objects never have to be refreshed. Modifying the properties of an object will immediately reflect in any other instances referring to the same object.

This aspect of RealmObject not only keeps Realm fast and efficient, it allows your code to be simpler and more reactive. For example, if your UI code is dependent on a specific Realm object, you don’t need to worry about refreshing or re-fetching it before triggering a UI redraw.

You can subscribe to Realm notifications to know when Realm data in an object is updated, indicating when your app’s UI should be refreshed.

PrimaryKey Properties

The [PrimaryKey] attribute can be specified on one property in a RealmObject class. Declaring a PrimaryKey allows objects to be looked up and updated efficiently and enforces uniqueness for each value.

Only chars, integral types, and strings can be used as PrimaryKeys. There is no particular storage or performance advantage to using char or smaller integer types. They are supported only in case you already have a property of that type.

Putting the [PrimaryKey] attribute on multiple properties will compile but is validated at runtime and will throw an exception reporting that Schema validation failed, as soon as you try to open that Realm.

Once an object with a PrimaryKey is added to a Realm, the PrimaryKey cannot be changed.

You can retrieve an object by PrimaryKey very quickly using Realm.Find which performs more streamlined query construction than using LINQ, as well as using an index. It is overloaded to take string, character or integer keys, eg:

Collections

At runtime, both conform to the IRealmCollection<T> interface which in turn conforms to IReadOnlyList<T> and INotifyCollectionChanged and supports lazy enumeration - the size of the collection is known but objects are only loaded into memory as you iterate the collection.

Writes

All changes to an object (addition, modification, and deletion) must be done within a write transaction.

To share objects between threads or re-use them between app launches, you must persist them to a Realm, an operation which must be done within a write transaction.

Since write transactions incur non-negligible overhead, you should architect your code to minimize the number of write transactions, i.e. if inserting multiple items in a loop, prefer to do it in a single transaction, rather than creating a transaction for each item, e.g.:

Because write transactions could potentially fail like any other disk IO operations, you should be prepared to handle exceptions from writes so you can handle and recover from failures like running out of disk space. There are no other recoverable errors. For brevity, our code samples don’t handle these errors but you certainly should in your production applications.

After you have created the object, all changes you make to it will be persisted (and must be made within a write transaction). Any changes are made available to other threads that use the same Realm when the write transaction is committed.

Please note that writes block each other, and will block the thread they are made on if multiple writes are in progress. We recommend you offload your writes to a separate thread.

Due to Realm’s MVCC architecture, reads are not blocked while a write transaction is open. Unless you need to make simultaneous writes from many threads at once, you should favor larger write transactions that do more work over many fine-grained write transactions.

Updating Objects

You can update any object by setting its properties within a write transaction.

// Update an object with a transaction
using(vartrans=realm.BeginWrite()){author.Name="Thomas Pynchon";trans.Commit();}

For objects where you have specified a [PrimaryKey], you can pass in update: true in realm.Add to add the passed in object or update the existing one:

If you specify update: true and pass in a class that does not have a PrimaryKey, the method will not be able to find object to update, so it will behave as if update: false was passed. If your object has relationships with other RealmObjects, they will be added or updated when they have PrimaryKey specified, or simply added, when they don’t:

The first statement gives you a new instance johnsAndPeters of a class that implements IQueryable and can be used to find the users with the name “John” or “Peter”. This is standard LINQ implementation - you get an object representing the query. The query doesn’t do anything until you make a further call that needs to iterate or count the results.

The ToList call, in this example, fires off the query which maps straight to the Realm core.

Objects are not copied - you get a list of references to the matching objects, and you work directly with the original objects that match your query.

Instead of retrieving them all into a list, you could also iterate through the query results, with the standard C# foreach statement:

Retrieving objects by type

To get all objects of a given type from a Realm, just use realm.All<T>(). It returns an IQueryable collection of all instances of the model class being queried - Person in the example above.

You can then choose to apply a LINQ query further to restrict the set. Remember, until you start iterating the collection, there’s no overhead.

varap=realm.All<Person>();// this is all items of a type
varscorers=ap.Where(p=>p.Score>35);// restrict with first search clause
varscorerDoe=scorers.Where(p=>p.LastName=="Doe");//effectivelyanANDclause

Sorting

The standard LINQ clauses OrderBy, OrderByDescending, ThenBy, and ThenByDescending can be used to specify a multi-level sort that affects the order of objects supplied by the Queryable returned from Realm.All or subsequent LINQ clauses.

They work via the internal query engine to provide efficient sorted access without loading all objects in the results.

Warning: If you use the ToList clause to extract a list of objects and then use an OrderBy you are sorting in-memory using LINQ for Objects. Make sure you only use ToList at the end of your expression.

Limiting Results

Most other database technologies provide the ability to paginate results from queries (such as the LIMIT keyword in SQLite). This is often done out of necessity to avoid reading too much from disk, or pulling too many results into memory at once.

Since queries in Realm are lazy, performing this sort of paginating behavior isn’t necessary at all, as Realm will only load objects from the results of the query once they are explicitly accessed.

If for UI-related or other implementation reasons you require a specific subset of objects from a query, it’s as simple as taking the IQueryable object, and reading out only the objects you need.

While you may be tempted to use the LINQ Take, that is not yet supported. When added, it will enumerate and instantiate all the objects you request in one operation.

Realms

A Realm is an instance of a Realm Database container. Realms can be local or synchronized. A synchronized Realm uses the Realm Object Server to transparently synchronize its contents with other devices. While your application continues working with a synchronized Realm as if it’s a local file, the data in that Realm might be updated by any device with write access to that Realm. In practice, your application works with any kind of Realm the same way, although opening a synchronized Realm requires a User that’s been authenticated to the Object Server and that’s authorized to open that Realm.

In the configuration you can also specify the schema version. For details about this, see the Migrations section. While developing, you can also set the property ShouldDeleteIfMigrationNeeded to true. This will cause Realm.GetInstance() to delete the existing database in case your schema mismatches that in the file being opened. This makes it easier to play around with models before releasing. However, do not release an app with this flag. You might want to set it within an #if DEBUG section to avoid accidents.

You can pass around an instance of a configuration, to open all your Realms with the same settings. This is the most common use for opening the same Realm in different threads.

You can also override the default configuration to change the defaults without having to pass around an object.

It is important to note that Realm instances are per-configuration, per-thread singletons. This means that Realm.GetInstance() will return the same instance every time it’s called on the same thread for the same configuration.

The Default Realm

Calling Realm.GetInstance() without passing any arguments returns the “default Realm” instance. The default Realm simply maps to a file called default.realm located in Environment.SpecialFolder.Personal.

In-memory Realms

With an InMemoryConfiguration configuration, you can create a Realm that runs entirely in memory without being persisted to disk:

In-memory Realms might still use disk space if memory is running low, but all files created by an in-memory Realm will be deleted when the Realm is closed. Creating an in-memory Realm with the same identifier as a persisted Realm isn’t allowed - identifiers still have to be unique.

When all in-memory Realm instances with a particular identifier are disposed or garbage collected, that frees all that Realm’s data. To keep an in-memory Realm “alive” throughout your app’s execution, hold onto a reference to it.

Asynchronously Opening Realms

If opening a Realm might require a time-consuming operation, such as applying migrations, compaction or downloading the remote contents of a synchronized Realm, you should use the Realm.GetInstanceAsync API to perform all work needed to get the Realm to a usable state on a background thread before completing the returned Task<Realm>. You should also use Realm.GetInstanceAsync with Realms that the user has read permissions only.

In addition, synchronized Realms wait for all remote content available at the time the operation began to be downloaded and available locally. For example:

varuser=awaitUser.LoginAsync(credentials,serverUrl);varconfig=newQueryBasedSyncConfiguration();try{varrealm=awaitRealm.GetInstanceAsync(config);// Realm successfully opened, with all remote data available
}catch(Exceptionex){// Handle error that occurred while opening or downloading the contents of the Realm
}

Closing Realm Instances

The Realm class implements IDisposable in order to take care of native memory deallocation and file descriptors so instances will be closed automatically when variables go out of scope.

Finding a Realm File

If you need help finding your app’s Realm file, check this StackOverflow answer for detailed instructions.

Auxiliary Realm Files

Alongside the standard .realm files, Realm also generates and maintains additional files for its own internal operations.

.realm.lock - A lock file for resource locks.

.realm.note - A named pipe for notifications.

These files don’t have any effect on .realm database files, and won’t cause any erroneous behavior if their parent database file is deleted or replaced.

When reporting Realm issues, please be sure to include these auxiliary files along with your main .realm file as they contain useful information for debugging purposes.

Bundling a Realm with an App

If you want to bundle a Realm with your app, see this StackOverflow answer which explains how to include files in Xamarin projects as resources and copy them for use.

Class Subsets

In some scenarios you may wish to limit which classes can be stored in a specific Realm.

classLoneClass:RealmObject{publicstringName{get;set;}}varconfig=newRealmConfiguration("RealmWithOneClass.realm");config.ObjectClasses=new[]{typeof(LoneClass)};// or specifying two classes in the Realm
config.ObjectClasses=new[]{typeof(Dog),typeof(Cat)};

Compacting Realms

Over the course of using your application, the memory used by Realm might become fragmented and take up more space than necessary. To rearrange the internal storage and potentially reduce the filesize, you can compact the Realm file by specifying a RealmConfiguration.ShouldCompactOnLaunch callback when opening a Realm file:

varconfig=newRealmConfiguration{ShouldCompactOnLaunch=(totalBytes,usedBytes)=>{// totalBytes refers to the size of the file on disk in bytes (data + free space)
// usedBytes refers to the number of bytes used by data in the file
// Compact if the file is over 100MB in size and less than 50% 'used'
varoneHundredMB=100*1024*1024;returntotalBytes>oneHundredMB&&(double)usedbytes/totalBytes<0.5;}};try{varrealm=Realm.GetInstance(config);}catch(Exceptione){// handle error compacting or opening Realm
}

The Realm will be compacted if you return true from the ShouldCompactOnLaunch delegate and the Realm file is not currently in use.

Alternatively, you can compact the file without obtaining a Realm instance by calling Realm.Compact(config):

varconfig=newRealmConfiguration("my.realm");Realm.Compact(config);

Notes on compacting

There should not be any open realm instances that use the file.

The file system should have free space for at least a copy of the Realm file.

If any operation fails, the Realm file is left untouched.

The method will return true if the operation is successful and false if there are open Realm instances accessing the same file.

At the moment, we don’t provide API for estimating the potential size gain by compacting a Realm. The recommended approach is to monitor your database’s size between launches and compact it if it crosses some threshold.

Deleting Realm Files

In some cases, such as clearing caches, or resetting your entire dataset, it may be appropriate to completely delete a Realm file from disk.

Unlike most files, Realm files are memory-mapped and Realm instances expect the files to be available for the duration of the instance’s lifetime.

Threading

Within individual threads, you can just treat everything as regular objects without worrying about concurrency or multithreading. There is no need for any locks or resource coordination to access them (even if they are simultaneously being modified on other threads) and it is only modifying operations that have to be wrapped in transactions.

Realm makes concurrent usage easy by ensuring that each thread always has a consistent view of the Realm. You can have any number of threads working on the same Realms in parallel, and since they all have their own snapshots, they will never cause each other to see inconsistent state.

The only thing you have to be aware of is that you cannot have multiple threads sharing the same instances of Realm objects. If multiple threads need to access the same objects, they will each need to get their own instances (otherwise changes happening on one thread could cause other threads to see incomplete or inconsistent data).

Seeing Changes From Other Threads

On the main UI thread (or any thread with a runloop/looper), objects will automatically update with changes from other threads between each iteration of the runloop. At any other time you will be working on the snapshot, so individual methods always see a consistent view and never have to worry about what happens on other threads.

When you initially open a Realm on a thread, its state will be based off the most recent successful write commit, and it will remain on that version until refreshed. Realms are automatically refreshed at the start of every runloop iteration. If a thread has no runloop (which is generally the case in a background thread), then Realm.Refresh() must be called manually in order to advance the transaction to the most recent state.

Failing to refresh Realms on a regular basis could lead to some transaction versions becoming “pinned”, preventing Realm from reusing the disk space used by that version, leading to larger file sizes. Refer to our Current Limitations for more details on this effect.

Passing Instances Across Threads

Persisted instances of Realm, RealmObject, IQueryable returned from Realm.All, or IList properties of RealmObjects can only be used on the thread on which they were created, otherwise an exception is thrown. This is one way Realm enforces transaction version isolation. Otherwise, it would be impossible to determine what should be done when an object is passed between threads at different transaction versions without a potentially extensive relationship graph.

Realm exposes a mechanism to safely pass thread-confined instances in three steps:

A ThreadSafeReference object must be resolved at most once. Failing to resolve it will result in the source version of the Realm being pinned until the reference is deallocated. For this reason, ThreadSafeReference should be short-lived.

ThreadSafeReference wrappers are provided for RealmObject, IList<RealmObject>, and IQueryable<RealmObject. They should only be used for persisted instances only, as the standalone versions of those are intrinsically not thread confined.

Using a Realm Across Threads

To access the same Realm file from different threads, you must initialize a new Realm to get a different instance for every thread of your app. As long as you specify the same configuration, all Realm instances will map to the same file on disk.

Sharing Realm instances across threads is not supported. Realm instances accessing the same realm file must also all use the same RealmConfiguration.

Asynchronous Writes

The Realm.WriteAsync() method is a special form of Write which makes it easy to offload the UI thread by performing writes on a background thread.

Caution:WriteAsync opens a temporary Realm instance, which is passed to your lambda as a parameter, seen in the example below. Be careful to only use the passed-in instance in the lambda and not the original thread’s realm. Due to the way lambdas capture the calling context, failing to change this code will not get a compiler error but instead a runtime exception will be thrown.

When its threaded action is complete, WriteAsync also calls Realm.Refresh() to advance the read state of the original (usually UI) thread. That thread will immediately receive notifications of any changes in the background threads.

There is no point using WriteAsync from code which you know is already running on a worker thread as it will just forward a call to Write without creating an extra thread. However, it is quite safe to use from any thread and adds no meaningful overhead. It is important to consider that on a background thread, WriteAsync will operate on the currentRealm instance, rather than create a new instance.

In general, since realm writes are very fast, we recommend using Write for interface-driven changes (e.g. the user types some string, or checks a checkbox) where only a few values change at a time. WriteAsync is useful in scenarios where there are hundreds or thousands of changes (e.g. fetching objects from the network or batch updating multiple objects) and performing them synchronously might lead to interface jitters.

Realm Notifications

If you have a background thread adding data to a Realm, your UI or other threads can get notified of changes in a Realm by adding a listener, which is executed when the Realm is changed (also by another thread or process):

Object Notifications

If you subscribe to the PropertyChangedEvent event on your class, your handler will be triggered when the Balance property is changed.

varaccount=newAccount();realm.Write(()=>realm.Add(account));account.PropertyChanged+=(sender,e)=>{Debug.WriteLine($"New value set for {e.PropertyName}");}realm.Write(()=>account.Balance=10);//=>"New value set for Balance"

Note that it doesn’t matter whether you subscribe before or after adding the object to the Realm. The event will be raised as expected in either case.

This is handy in and of itself, but furthermore, it enables databinding with Xamarin.Forms. For more info, see From Data Bindings to MVVM in the Xamarin Docs.

Collection Notifications

IQueryable objects returned from Realm.All<T>() or subsequent LINQ clauses are live queries, meaning that they are always kept up to date. Any time you iterate over the collection, you will get a result that is up to date with the latest changes. Similarly IList properties on RealmObjects represent live to-many relationships, meaning that each time you iterate over them, you will get the most up-to-date collection of related objects.

The runtime objects backing both of these collections also implement IRealmCollection<T> which means that it exposes two mechanisms for subscribing for change notifications. We’ve provided a convenience extension method: AsRealmCollection that will cast an IList<T> or IQueryable<T> to IRealmCollection<T>.

Alternatively, if you wish more detailed change information, that is useful for manipulating a UITableView or ListView directly (e.g. in a Xamarin Native UI project), you can use the SubscribeForNotifications extension method. You give this method a delegate that will be called with a change set, telling you what has been added, removed or modified.

Migrations

When working with any database, it is likely your data model will change over time. Since data models in Realm are defined as standard C# classes, making model changes is as easy as changing any other class. For example, suppose we have the following Person model:

At this point if you had saved any data with the previous model version, there will be a mismatch between what Realm sees defined in code and the data Realm sees on disk. When this occurs, an exception will be thrown when you try to open the existing file unless you run a migration.

Performing a Migration

The minimal solution you can perform is to bump the schema version. When unspecified, Realms will have a schema version set to 0. As soon as you make a schema change, you must increase the schema version in your configuration. This way, we avoid accidental schema changes that potentially destroy data.

Now, if you do nothing more than this and run it with a database file that was created with the old schema, all the FirstName and LastName entries will be deleted and every Person will have an empty FullName property. This probably isn’t what you wanted here. So you must tell Realm how to handle the migration.

Note that if you simply rename a class or a property, Realm will not be able to detect that and you will have to copy data in the migration as well.

This callback function will be called exactly once when a Realm with a lower version is opened. You should migrate all updated classes during that call.

As our Person model no longer contains the FirstName and LastName properties, we cannot access those through the typed API. However, we can utilize the dynamic API and achieve the same thing.

varconfig=newRealmConfiguration{SchemaVersion=1,MigrationCallback=(migration,oldSchemaVersion)=>{varnewPeople=migration.NewRealm.All<Person>();// Use the dynamic api for oldPeople so we can access
// .FirstName and .LastName even though they no longer
// exist in the class definition.
varoldPeople=migration.OldRealm.All("Person");for(vari=0;i<newPeople.Count();i++){varoldPerson=oldPeople.ElementAt(i);varnewPerson=newPeople.ElementAt(i);newPerson.FullName=oldPerson.FirstName+" "+oldPerson.LastName;}}};varrealm=Realm.GetInstance(config);

As your app grows older and you have multiple changes to the model in different versions, you make a sequence of migrations by inspecting the oldSchemaVersion parameter to your callback. Let’s say you change the Person model further by changing the Age field to a Birthday field:

This is then version 2 of the schema, and your migration setup could now look something like the following:

varconfig=newRealmConfiguration{SchemaVersion=2,MigrationCallback=(migration,oldSchemaVersion)=>{varnewPeople=migration.NewRealm.All<Person>();varoldPeople=migration.OldRealm.All("Person");for(vari=0;i<newPeople.Count();i++){varoldPerson=oldPeople.ElementAt(i);varnewPerson=newPeople.ElementAt(i);// Migrate Person from version 0 to 1: replace FirstName and LastName with FullName
if(oldSchemaVersion<1){newPerson.FullName=oldPerson.FirstName+" "+oldPerson.LastName;}// Migrate Person from version 1 to 2: replace Age with Birthday
if(oldSchemaVersion<2){newPerson.Birthday=DateTimeOffset.Now.AddYears(-(int)oldPerson.Age);}}}};varrealm=Realm.GetInstance(config);

Encryption

Please take note of the Export Compliance section of our LICENSE, as it places restrictions against the usage of Realm if you are located in countries with an export restriction or embargo from the United States.

Realm supports encrypting the database file on disk with AES-256+SHA2 by supplying a 64-byte encryption key when creating a Realm.

varconfig=newRealmConfiguration("Mine.realm");config.EncryptionKey=newbyte[64]// key MUST be exactly this size
{0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78};varrealm=Realm.GetInstance(config);//willcreate/openencryptedrealm"Mine.realm"

This makes it so that all of the data stored on disk is transparently encrypted and decrypted with AES-256 as needed, and verified with a SHA-2 HMAC. The same encryption key must be supplied every time you obtain a Realm instance.

You should use a key that is unique to your app, not the one in the example above. Furthermore, if you need unique keys for each user, look into the Xamarin.Auth API.

There is a small performance hit (typically less than 10% slower) when using encrypted Realms.

Sync

The Realm Platform (RP) extends the Realm Database across the network, enabling automatic synchronization of data across devices. In order to do this, a new set of types and classes are provided that support these synchronized Realms; these new classes are additive to the existing Realm Database and are covered here.

Enabling Realm Platform

No explicit steps are required to enable Realm Platform. It is installed by default in the standard Realm NuGet.

Users

The central object in the Realm Object Server is the concept of a Realm User—a User—that is associated with a synchronized Realm. The User can be authenticated to a shared Realm via a username/password scheme or through a number of 3rd party authentication methods.

The username and password authentication is entirely managed by the Realm Object Server, giving you full control over your application’s user management. For other authentication methods, your application is responsible for logging into the external service and obtaining the authentication token.

Here are some examples of setting credentials with various providers.

JSON Web Token

The JWT authentication provider allows you to integrate with an existing authentication system. It requires that your authentication server generates a signed JWT, which the client sends to the Realm Object Server for verification.

vartoken="...";// a string representation of a JWT, obtained from your auth server
varcredentials=Credentials.JWT(token);

Username/Password

The third parameter of UsernamePassword() is the createUser flag which should only be true the first time, as it indicates that the user should be created. Once the user is created, the parameter must be set to false.

Alternatively, you can require that all users are created in advance on the server using an admin Dashboard, and always pass false for the createUser parameter.

We strongly recommend using HTTPS when using the Username/Password authentication flow as otherwise, sensitive user data may be intercepted by third parties.

Nickname

The Nickname provider allows you to authenticate users just by their nickname without requiring passwords or other identifying information. This is useful when prototyping collaborative features for your app without worrying about the actual login flow until later in the development lifecycle.

The Nickname provider is not secure and should never be enabled in production deployments. It’s meant to only be used during development.

varcredentials=Credentials.Nickname("some-nickname",isAdmin:false);

Anonymous

Sometimes it’s useful to create a synchronized Realm for a user without prompting them for credentials - e.g. in an e-commerce application where any disruption leads to user churn. For such cases, the Realm Object Server exposes an anonymous provider that requires no payload and creates a new user for every request (which means that you must use User.Current to avoid resetting the state on every launch).

varcredentials=Credentials.Anonymous();

Google

vartoken="...";// a string representation of a token obtained by Google Login API
varcredentials=Credentials.Google(token);

Facebook

vartoken="...";// a string representation of a token obtained by Facebook Login API
varcredentials=Credentials.Facebook(token);

Azure Active Directory

vartoken="...";// a string representation of a token obtained by logging in with Azure Active Directory
varcredentials=Credentials.AzureAD(token);

Custom Auth

vartoken="...";// a string representation of a token obtained from your custom provider
varcredentials=Credentials.Custom("myAuth",token,null);

Additional information can be passed to a custom auth provider in the form of a dictionary provided as the third parameter; see the API Reference for details.

Logging in the User

Now, with all the required parameters the user can be logged into the Realm Object Server:

Logging Out

When a user is logged out, the synchronization will stop. A logged out user can no longer open a Realm using a SyncConfiguration.

Configuring user persistence

By default, Realm will persist logged in users across application launches. You can modify that behavior by calling User.ConfigurePersistence. The available modes are

Disabled: users will not be persisted by Realm. This means that you either need to store user credentials manually, or ask the user to login every time they launch the application.

NotEncrypted: User credentials will be stored unencrypted. This option is not recommended for production applications as it provides a vector of attack for stealing user identities.

Encrypted: User credentials are stored encrypted. If you choose to use that option, you must provide a valid encryptionKey.

By default, Realm uses Encrypted mode on iOS and stores the encryptionKey in the iOS Keychain. On Android, NotEncrypted is used because the AndroidKeyStore API is only supported on API level 18 and up. It is recommended that you opt in for Encrypted mode on Android and provide encryptionKey that is unique to your application or target at least API level 18 and store a unique per-user encryptionKey in the KeyStore.

The configuration ties together an authenticated user and a sync server URL. The sync server URL may contain the tilde character (“~”) which will be transparently expanded to represent the user’s unique identifier. This scheme easily allows you to write your app to cater to its individual users. The location on disk for shared Realms is managed by the framework, but can be overridden if desired.

varserverURL=newUri("/some-realm",UriKind.Relative);varconfiguration=newQueryBasedSyncConfiguration(serverURL,user);// If there's only one logged-in user, the user argument may be omitted:
varconfiguration=newQueryBasedSyncConfiguration(serverURL);

If you have not disabled user persistence, User.Current can be used to obtain the currently logged in user. If no users have logged in or all have logged out, it will return null. If there are more than one logged in users, a RealmException will be thrown.

varuser=User.Current;

If there are likely to be multiple users logged in, you can get a collection of them by calling User.AllLoggedIn. This will be empty if no users have logged in.

varusers=User.AllLoggedIn;foreach(varuserinusers){// do something with the user
}

The subscription callback will be invoked periodically by the synchronization subsystem. As many subscribers as needed can be registered on a session object simultaneously. Subscribers can either be configured to report upload progress or download progress. Each time a subscriber is called, it will be passed a SyncProgress instance that will contain information about the current number of bytes already transferred, as well as the total number of transferable bytes (defined as the number of bytes already transferred plus the number of bytes pending transfer).

Each time a subscriber is registered, an IDisposable token will be returned. You must keep a reference to that token for as long as progress notifications are desired. To stop receiving notifications, call Dispose on the token.

ReportIndefinitely - the subscription will stay active until Dispose is explicitly called and will always report the most up-to-date number of transferrable bytes. This type of callback could be used to control a network indicator UI that, for example, changes color or appears only when uploads or downloads are actively taking place.

ForCurrentlyOutstandingWork - the subscription will capture the number of transferable bytes at the moment it is registered and always report progress relative to that value. Once the number of transferred bytes reaches or exceeds that initial value, the subscriber will automatically unregister itself. This type of subscription could, for example, be used to control a progress bar that tracks the progress of an initial download of a synced Realm when a user signs in, letting them know how long it is before their local copy is up-to-date.

Note that those examples use the ObservableExtensions.Subscribe extension method to simplify subscribing. We recommend using the Reactive Extensions class library as it greatly simplifies working with observable sequences. For example, here’s a more advanced scenario, where both upload and download progress is tracked, throttled, and finally, dispatched on the main thread:

Access Control

The Realm Platform provides flexible access control mechanisms to restrict which users are allowed to sync against which Realm files. This can be used, for example, to create collaborative apps where multiple users write to the same Realm. It can also be used to share data in a publisher/subscriber scenario where a single writing user shares data with many users with read permissions.

These instructions apply only when using fully synchronized Realms (opened with a FullSyncConfiguration instance). Query-based synchronized Realms have their own fine-grained permission system that works at the object level. You can read more about it here.

There are three axes that control the access level (permissions) of a given Realm:

Read indicates that the user is allowed to read from the Realm.

Write indicates that the user is allowed to write to the Realm.

Admin indicates that the user is allowed to change the permissions for the Realm.

Unless permissions are explicitly modified, only the owner (creator) of a Realm can access it. The only exception is admin users: They are always granted all permissions to all Realms on the server.

Please refer to the general Realm Object Server documentation on Access Control to learn more about the concept.

To get permissions granted by a user, pass in Recipient.OtherUser. The millisecondTimeout argument controls the maximum time to wait for response from the server. When the timeout elapses, the last known state is returned, so even if the client is currently offline, some data may still be shown.

Modifying Permissions

Modifying the access control settings for a Realm file is performed by either applying permissions directly or offering them.

Granting Permissions

Permission changes can be applied (i.e. granted or revoked) via the User.ApplyPermissionsAsync method in order to directly increase or decrease other users’ access to a Realm.

UserId - use this to apply permissions based on a user’s Identity(the internal Id that Realm generates).

Email - use this to change permissions by specifying a user’s email (username) in the Username/Password provider.

The last argument controls the AccessLevel that the user will be granted. Higher access implies all lower tiers, e.g. Write implies Read, Admin implies Read and Write. If AccessLevel.None is passed, this will revoke the user’s permissions for this Realm.

Offer/Response

A user can offer permissions to their Realm by sharing the opaque token returned by OfferPermissionsAsync:

The optional expiresAt argument controls when the offer expires - i.e. using the token after that date will no longer grant permissions to that Realm. Users who have already consumed the token to obtain permissions will not lose their access after that date. If you want to revoke it, use ApplyPermissionsAsync.

Once a user has received a token, e.g. by sharing it via messaging app, or scanning a QR code, they can consume it to obtain the permissions offered:

vartoken="...";varrealmUrl=awaituserB.AcceptPermissionOfferAsync(token);// Use the realmUrl to open the Realm
varconfig=newFullSyncConfiguration(newUri(realmUrl),userB);varrealm=awaitRealm.GetInstanceAsync(config);

Retrieving existing offers/changes

Sometimes, it may make sense to retrieve existing management objects, e.g. to invalidate an offer or to attach a change listener after an app has been restarted.

If you want to invalidate a PermissionOffer and prevent new users from consuming the token, use the InvalidateOfferAsync method:

// Get all offers that grant write permissions and have no expiration date
varoffers=user.GetPermissionOffers(ManagementObjectStatus.Success).Where(s=>s.MayWrite&&s.ExpiresAt==null);foreach(varofferinoffers){awaituser.InvalidateOfferAsync(offer);}

Error reporting

Certain sync-related APIs perform asynchronous operations that may fail and those will raise exceptions that can be observed in a try-catch block.

It is strongly recommended to also subscribe to the Session.Error event. Errors involving the global synchronization subsystem or specific sessions (which represent Realms opened for synchronization with the server) will be reported to this handler. When errors occur, the error handler will be invoked with ErrorEventArgs containing the Exception, as well as a Session object representing the session the error occurred on.

Session.Error+=(session,errorArgs)=>{// handle error
};

Errors

Realm Platform errors are represented by SessionExceptions. In addition to the standard exception properties, you have access to an ErrorCode that contains information about the type of the error and allows you to have strongly typed handling logic, e.g.:

Session.Error+=(session,errorArgs)=>{varsessionException=(SessionException)errorArgs.Exception;switch(sessionException.ErrorCode){caseErrorCode.AccessTokenExpired:caseErrorCode.BadUserAuthentication:// Ask user for credentials
break;caseErrorCode.PermissionDenied:// Tell the user they don't have permissions to work with that Realm
break;caseErrorCode.Unknown:// Likely the app version is too old, prompt for update
break;// ...
}};

Client Reset

If a Realm Object Server crashes and must be restored from a backup, there is a possibility that an app might need to carry out a client reset on a given synced Realm. This will happen if the local version of the Realm in question is greater than the version of that same Realm on the server (for example, if the application made changes after the Realm Object Server was backed up, but those changes weren’t synced back to the server before it crashed and had to be restored).

The client reset procedure is as follows: a backup copy of the local Realm file is made, and then the Realm files are deleted. The next time the app connects to the Realm Object Server and opens that Realm, a fresh copy will be downloaded. Changes that were made after the Realm Object Server was backed up but weren’t synced back to the server will be preserved in the backup copy of the Realm, but will not be present when the Realm is re-downloaded.

If the method is called to manually initiate the client reset process, all instances of the Realm in question must first be closed by calling Dispose() before the method is invoked. However, doing so allows the Realm to be immediately re-opened after the client reset process is complete, allowing syncing to resume.

If InitiateClientReset is not called, the client reset process will automatically take place after the next time the app is launched, upon first obtaining a Realm instance. It is the app’s responsibility to persist the location of the backup copy if needed, so that the backup copy can be found later.

A Realm which needs to be reset can still be written to and read from, but no subsequent changes will be synced to the server until the client reset is complete and the Realm is re-downloaded. It is extremely important that your application listen for client reset errors and, at the very least, make provisions to save user data created or modified after a client reset is triggered so it can later be written back to the re-downloaded copy of the Realm.

The following example shows how the client reset APIs might be used to carry out a client reset:

For more information about how the Realm Object Server handles client reset, please refer to our server documentation.

Migrations

Automatic migrations are supported for synced Realms. At present only additive changes are supported, such as adding a class or field to an existing class. Any non-additive changes will lead to an exception being thrown.

Migrations will automatically be triggered if needed. There is no need to set either a custom migration callback or a schema version number.

Conflict Resolution

Query-based synchronization

Query-based synchronization is a feature that allows a synchronized Realm to be opened in a such a way that it does not download all objects stored within the remote Realm on the server. Instead, a partially synced Realm allows you to specify what subset of objects you want synchronized to the local copy using queries.

Subscribing to data

By default, a query-based synchronized Realm contains no data. Instead, the client application must choose, or subscribe to, which data it wants to partially synchronize from the overall Realm maintained on the server.

Subscribing to data is easy as it utilizes Realm’s query system. Applications can create any number of queries for data which will be transmitted to the server and evaluated. The results of the query will then be synced to the application. The underlying sync protocol ensures that objects are only sent once in the case that an object matches several queries an application has subscribed to.

Subscriptions are automatically persisted and maintained by the server. When data changes occur the server will reevaluate existing subscriptions and push the changes to all clients.

varsubscription=realm.All<Person>().Where(p=>p.Age>18).Subscribe();

Subscribe() registers the query with the server, and returns a Subscription object which can be used to observe the current state of the subscription or to remove it. A subscription can also be given an explicit name by passing the desired name to Subscribe():

Registering for notifications

Working with a synced Realm is no different than a local Realm (other than it is automatically synchronized). As a result, you can utilize Realm’s existing notification functionality to register for changes that occur through synchronization.

When you are using Query-based synchronization, the notification system is critical because you will need to know when the server has fulfilled the initial subscription in addition to later data changes.

varsubscription=realm.All<Person>().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){caseSubscriptionState.Creating:// The subscription has not yet been written to the Realm
break;caseSubscriptionState.Pending:// The subscription has been written to the Realm and is waiting
// to be processed by the server
break;caseSubscriptionState.Complete:// The subscription has been processed by the server and all objects
// matching the query are in the local Realm
break;caseSubscriptionState.Invalidated:// The subscription has been removed
break;caseSubscriptionState.Error:// An error occurred while processing the subscription
varerror=subscription.Error;break;}};subscription.Results.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.
};

Unsubscribing

If a client does not need the data from a subscription anymore, it can choose to unsubscribe. This does not delete the objects, but instead simply removes them from the client device. For example, if an application provides user-driven search (which creates a subscription), it might choose to keep only the results from the last query to limit data stored on the device.

varsubscription=realm.All<Person>().Where(p=>p.Age>18).Subscribe();awaitsubscription.UnsubscribeAsync();// Alternatively, for named subscriptions, you can also unsubscribe
// by their name:
varnamed=realm.All<Person>().Where(p=>p.Age>18).Subscribe("legal-drivers");awaitSubscription.UnsubscribeAsync("legal-drivers");

Migrating From Realm Object Server 1.* to 2.*

If you were using a prior version of Realm alongside a version of Realm Object Server prior to 2.0, and you upgrade your application to use Realm Object Server 2.0 or later, you must write code in your application to handle migrating your local copies of synchronized Realms. The Realm Object Server 2.0 file format is incompatible with earlier versions of the Realm Object Server, and all Realms that were synced from an older version of the Realm Object Server must be re-downloaded.

When a synced Realm requiring migration is opened, the Realm file will be copied to a backup location and then deleted so that it can be re-downloaded from the Realm Object Server. After that an Incompatible​Synced​File​Exception will then be thrown.

varconfig=newQueryBasedSyncConfiguration();Realmrealm;try{realm=Realm.GetInstance(config);// Realm successfully opened, proceed as usual
}catch(IncompatibleSyncedFileExceptionex){// The old Realm was created with a previous version of the SDK. Migrate to the new one.
varbackupConfig=ex.GetBackupRealmConfig();varbackupRealm=Realm.GetInstance(backupConfig);// Reopen the Realm using the original config - it will now be empty
realm=Realm.GetInstance(config);// Migrate any data from backupRealm to realm
realm.Write(()=>{foreach(varpersoninbackupRealm.All("Person")){// Either migrate manually or use AutoMapper or similar tool
// to automate most of the process.
realm.Add(newPerson{Name=person.Name,Age=person.Age});}});}

Current Limitations

Realm is generally trying to have as few constraints as possible and we are continuously adding new features based on feedback from the community. However, Realm still has a few limitations. These have been compiled below.

Please refer to our GitHub issues for a more comprehensive list of known issues.

General Limits

Realm aims to strike a balance between flexibility and performance. In order to accomplish this goal, realistic limits are imposed on various aspects of storing information in a realm. For example:

Class names must be between 0 and 57 bytes in length. UTF-8 characters are supported. An exception will be thrown at your app’s initialization if this limit is exceeded.

Property names must be between 0 and 63 bytes in length. UTF-8 characters are supported. An exception will be thrown at your app’s initialization if this limit is exceeded.

iOS Limitation: The total size of all open Realm files cannot be larger than the amount of memory your application would be allowed to map in iOS — this changes per device, and depends on how fragmented the memory space is at that point in time (there is a radar open about this issue: rdar://17119975). If you need to store more data, you can split into multiple Realm files, and open and close them as needed.

Threads

Although Realm files can be accessed by multiple threads concurrently, you cannot hand over Realms, Realm objects, queries, and results between threads. Read more about Realm’s threading.

File size & tracking of intermediate versions

You should expect a Realm database to take less space on disk than an equivalent SQLite database. If your Realm file is much larger than you expect, it may be because you have a RealmObject that is referring to an older version of the data in the database.

In order to give you a consistent view of your data, Realm only updates the active version accessed at the start of a run loop iteration. This means that if you read some data from the Realm and then block the thread on a long-running operation while writing to the Realm on other threads, the version is never updated and Realm has to hold on to intermediate versions of the data which you may not actually need, resulting in the file size growing with each write. The extra space will eventually be reused by future writes.

FAQ

Is Realm open source?

Yes! Realm’s internal C++ storage engine and the language SDKs over it are entirely open source and licensed under Apache 2.0. Realm also optionally includes a closed-source Realm Platform Extensions component, but that is not required to use Realm as an embedded database.

Building Realm in a CI environment

The Realm build tasks depend on the $(SolutionDir) property being set by MSBuild. This happens when building via the solution file which is why things work out of the box on Visual Studio. In CI environments (e.g. VSTS, Jenkins, Appveyor), often you invoke the msbuild command line tool for individual projects which leaves $(SolutionDir) undefined. To fix that, you’ll need to pass /p:SolutionDir=/path/to/solution/folder to the msbuild command invocation. In most CI environments, the solution directory will be the current folder, ., but this may not apply to all. Refer to your automation server’s documentation for more details.

I see a network call to Mixpanel when I build my app, what is that?

Realm collects anonymous analytics when you run the Realm assembly weaver on your assemblies containing RealmObject classes. This is completely anonymous and helps us improve the product by flagging which version of Realm you use and what OS you use, and what we can deprecate support for. This call does not run when your app is in production, or running on your user’s devices — only when your assemblies are woven by Fody during build. You can see exactly how & what we collect, as well as the rationale for it in our source code.

Does Realm work as a Portable (PCL) Library?

You need to use the iOS, Android, or Win32 version of Realm with your executable but we offer a PCL that you can use to compile against the Realm API with. This is the NuGet Bait and Switch Trick in action. If you add Realm to a PCL project via NuGet, and also add it to your executable, it will work.

Note that this PCL does not mean you can just use Realm on an arbitrary .NET platform. Realm relies on a native C++ core which has to be ported to each platform.

Troubleshooting

Crash Reporting

We encourage you to use a crash reporter in your application. Many Realm operations could potentially fail at runtime (like any other disk IO), so collecting crash reports from your application will help identify areas where either you (or us) can improve error handling and fix crashing bugs.

Most commercial crash reporters have the option of collecting logs. We strongly encourage you to enable this feature. Realm logs metadata information (but no user data) when throwing exceptions and in irrecoverable situations, and these messages can help debug when things go wrong.

Reporting Realm Issues

If you’ve found an issue with Realm, please either file an issue on GitHub or email us at help@realm.io with as much information as possible for us to understand and reproduce your issue.

The following information is very useful to us:

Goals.

Expected results.

Actual results.

Steps to reproduce.

Code sample that highlights the issue (full projects that we can compile ourselves are ideal).

In the second case, the exception will be thrown from ObjectSchema. We have had some users run into problems when they have the Linker Behaviour set to Link All and they lack the [Preserve(AllMembers = true)] attribute on the class declaration. The linker will only preserve members which are referenced explicitly in the code. This means that if you have a property that would be persisted but is not referenced anywhere, it might be removed causing the schema to mismatch that of the database.

By default, Realm builds the schema to describe all of your RealmObject subclasses in all your assemblies. This happens lazily and so is not triggered until your first call to GetInstance(). It will only do this a maximum of once per run, caching the result in memory.

Fody: Am unhandled exception occurred

This common build failure can easily be triggered when you have already built a project and just add a new RealmObject subclass.

Choosing Build or Run will not rebuild the project sufficiently to invoke the Fody Weaver.

Simply choose Rebuild on your project and it should build without error.

Failing to Weave

You may see a warning in the build log about classes not having been woven. This indicates that the Fody weaving package is not properly installed.

Firstly, check that the FodyWeavers.xml file contains an entry for RealmWeaver.

The installation will copy RealmWeaver.Fody.dll up into a Tools directly in your solution directory (this is usually a sibling to your project directories). It is not linked into any of the projects but needs to be in that location for Fody to find the DLL.

It is also possible that the installation of Fody has failed. This has been experienced with Visual Studio 2015 and versions of NuGet Package Manager prior to version 3.2. To diagnose this, use a text editor to check that your .csproj has a line importing Fody.targets, such as:

Troubleshooting WriteAsync Issues

Inside WriteAsync, we check for a non-null SynchronizationContext.Current to indicate if you might be on the UI thread. This check may be confused by a well-established pattern of programming used where people also set Current in their worker threads, so they can use the Post method to run code on the UI thread. This pattern dates back to a 2007 MSDN blog posting.

It is not a problem if you have set SynchronisationContext.Current but it will cause WriteAsync to dispatch again on the thread pool, which may create another worker thread. So, if you are using Current in your threads, consider calling just Write instead of WriteAsync.

Realm Core Binary Fails to Download

When building Realm, part of the process includes downloading the core library as a static binary and integrating it into the Realm project. This is part of the wrappers building by Makefile.

It’s been reported that in certain instances, the core binary fails to download with the following error:

Downloading core failed. Please try again once you have an Internet connection.

This error can occur due to any of the following reasons:

Your IP address range is from a region that is on the list of United States embargoes. In order to comply with U.S. law, Realm has not been made available in that region. For more information, please see our license.

You are located in mainland China, and due to the country-wide firewall you are not able to properly access CloudFlare or Amazon AWS S3 services at the moment. Please see this issue on one of our other products for more information.