Couchbase Mobile brings the power of NoSQL to the edge. It is comprised of three components:
Couchbase Mobile supports flexible deployment models. You can deploy
This tutorial will walk you through a very basic example of how you can use Couchbase Lite in standalone mode within your Xamarin Forms app for iOS, Android, and UWP.
You will learn the fundamentals of
You can learn more about Couchbase Mobile here.
This tutorial assumes familiarity with building apps with Xamarin, more specifically Xamarin.Forms using C# and XAML.
Note: If you are using an older version of Xcode, which you need to retain for other development needs, make a copy of your existing version of Xcode and install the latest Xcode version. That way you can have multiple versions of Xcode on your Mac. More information can be found in Apple's Developer Documentation.
Note: You can not edit or debug UWP projects with Visual Studio for Mac and you can't edit or debug Mac projects with Visual Studio for PC.
We will be working with a very simple User Profile app. It does one thing -- Allow a user to log in and create or update their user profile data.
The user profile data is persisted as a Document in the local Couchbase Lite Database. So, when the user logs out and logs back in again, the profile information is loaded from the Database.
git clone https://github.com/couchbase-examples/dotnet-xamarin-cblite-userprofile-standalone
UserProfileDemo.sln
. The project would be located at /path/to/userprofile-couchbase-mobile-xamarin/src
.open UserProfileDemo.sln
The User Profile demo app is a Xamarin.Forms based solution that supports iOS and Android mobile platforms along with the UWP desktop platform.
The solution utilizes various design patterns and principles such as MVVM, IoC, and the Repository Pattern.
The solution consists of seven projects.
.ipa
file..apk
or .aab
file..exe
file that can run on Windows.Now that you have an understanding of the solution architecture let's dive into the app!
Before diving into the code for the apps, it is important to point out the Couchbase Lite dependencies within the solution. The Couchbase.Lite Nuget package is included as a reference within four projects of this solution:
The Couchbase.Lite
Nuget package contains the core functionality for Couchbase Lite. In the following sections you will dive into the capabilities it the package provides.
In order to use Couchbase Lite within a Xamarin app for Android you will need to activate it.
Open MainActivity.cs in the UserProfileDemo.Android
project.
Couchbase.Lite.Support.Droid.Activate(this);
Couchbase Lite is a JSON Document Store. A Document
is a logical collection of named fields and values.The values are any valid JSON types. In addition to the standard JSON types, Couchbase Lite supports Date
and Blob
data types.
While it is not required or enforced, it is a recommended practice to include a "type" property that can serve as a namespace for related documents.
The app deals with a single Document
with a "type" property of "user". The document ID is of the form "user::demo@example.com"
.
An example of a document would be:
{
"type":"user",
"name":"Jane Doe",
"email":"jane.doe@earth.org",
"address":"101 Main Street",
"image":CBLBlob (image/jpg)
}
A special blob
data type that is associated with the profile image -- see Working with Blobs.
The "user" Document
is encoded to a class named UserProfile that resides in the UserProfileDemo.Models project.
public class UserProfile
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public byte[] ImageData { get; set; }
public string Description { get; set; }
}
In this section, we will do a code walkthrough of the basic Database operations
When a user logs in, we create an empty Couchbase Lite database for the user if one does not exist.
Database
property. When the Database
property is used for the first time a Couchbase Lite database will be opened, or created if it does not already exist via the instantiation of a new object.Database _database;
protected Database Database
{
get
{
if (_database == null)
{
_database = new Database(DatabaseName, DatabaseConfig);
}
return _database;
}
private set => _database = value;
}
DatabaseConfiguration
within UserProfileRepository.cs via an abstract
requirement from the parent class, BaseRepository
. This is an optional step. In our case, we would like to override the default path of the database. Every user has their own instance of the Database
that is located in a folder corresponding to the user. Please note that the default path is platform specific.DatabaseConfiguration _databaseConfig;
protected override DatabaseConfiguration DatabaseConfig
{
get
{
if (_databaseConfig == null)
{
if (AppInstance.User?.Username == null)
{
throw new Exception($"Repository Exception: A valid user is required!");
}
_databaseConfig = new DatabaseConfiguration
{
Directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
AppInstance.User.Username)
};
}
return _databaseConfig;
}
set => _databaseConfig = value;
}
_database = new Database(DatabaseName, DatabaseConfig);
You can be asynchronously notified of any change (add, delete, update) to the Database
by registering a change listener with the Database
. In our app, we are not doing anything special with the Database
change notification other than logging the change. In a real world app, you would use this notification for instance, to update the UI.
Database.AddChangeListener
function usage within the constructor.DatabaseListenerToken = Database.AddChangeListener(OnDatabaseChangeEvent);
OnDatabaseChangeEvent
. This is an optional step. The AddChangeListener
method returns a ListenerToken
. The ListenerToken
is required to remove the listener from the database. The listener is a delegate method that takes two parameters of type object
and DatabaseChangedEventArgs
respectively.void OnDatabaseChangeEvent(object sender, DatabaseChangedEventArgs e)
{
foreach (var documentId in e.DocumentIDs)
{
var document = Database?.GetDocument(documentId);
string message = $"Document (id={documentId}) was ";
if (document == null)
{
message += "deleted";
}
else
{
message += "added/updated";
}
Console.WriteLine(message);
}
}
When a user logs out, we close the Couchbase Lite database associated with the user, deregister any database change listeners, and free up memory allocations.
Open the BaseRepository.cs file and locate the Dispose
method. In our sample Dispose
handles the removal of database listeners, removing various objects from memory, and closing the database. Dispose
will be called when a user logs out.
public void Dispose()
{
DatabaseConfig = null;
Database.RemoveChangeListener(DatabaseListenerToken);
Database.Close();
Database = null;
}
For iOS on a Mac - this will open or create a database at path
/Users/[user_name]/Library/Developer/CoreSimulator/Devices/[unique_device_id]/data/Containers/Data/Application/[unique_app_id]/Library/Application Support/demo@example.com
Once an instance of the Couchbase Lite database is created/opened for the specific user, we can perform basic Document
functions on the database. In this section, we will walkthrough the code that describes basic Document
operations
Once the user logs in, the user is taken to the "Your Profile" screen. A request is made to load The "User Profile" Document for the user. When the user logs in the very first time, there would be no user profile document for the user.
userProfileDocId
definition. This document Id is constructed by prefixing the term "user::" to the username of the user.string UserProfileDocId => $"user::{AppInstance.User.Username}";
UserProfileViewModel
is tasked with retrieving the profile for a logged in user. It does this by using a class that implements IUserProfileRepository
.var up = UserProfileRepository?.Get(UserProfileDocId);
Get
function.public override UserProfile Get(string userProfileId)
userProfileDocId
from the database.var document = Database.GetDocument(userProfileId); // (1)
if (document != null)
{
userProfile = new UserProfile // (2)
{
Id = document.Id,
Name = document.GetString("Name"),
Email = document.GetString("Email"), // (3)
Address = document.GetString("Address"),
ImageData = document.GetBlob("ImageData")?.Content
}; // (4)
}
Document
from the database.email
property of the UserProfile with the username of the logged in user.Note: This value is not editable after it is not initially saved.
Document
. Specifically, note the support of the GetBlob
type to fetch the value of a property of type Blob
.A The "User Profile" Document is created for the user when the user taps the "Done" button on the "Profile Screen". The function below applies whether you are creating a document or updating an existing version
UserProfileViewModel
is tasked with setting values of a profile for a logged in user, and saving them to the database. It does this by using a class that implements IUserProfileRepository
.bool? success = UserProfileRepository?.Save(userProfile);
Save
function.public override bool Save(UserProfile userProfile)
Document
. By default, all APIs in Couchbase Lite deal with immutable objects, thereby making them thread-safe by design. In order to mutate an object, you must explicitly get a mutable copy of the object. Use appropriate type-setters to set the various properties of the Document
:var mutableDocument = new MutableDocument(userProfile.Id);
mutableDocument.SetString("Name", userProfile.Name);
mutableDocument.SetString("Email", userProfile.Email);
mutableDocument.SetString("Address", userProfile.Address);
mutableDocument.SetString("type", "user");
if (userProfile.ImageData != null)
{
mutableDocument.SetBlob("ImageData", new Blob("image/jpeg", userProfile.ImageData));
}
Specifically, note the support of the
SetBlob
type to fetch the value of a property of typeBlob
.
Database.Save(mutableDocument);
We do not delete a Document
in this sample app. However, deletion of a document is pretty straightforward and this is how you would do it.
var document = Database.GetDocument(id);
if (document != null)
{
Database.Delete(document);
}
Congratulations on completing this tutorial!
This tutorial walked you through a very basic example of how to get up and running with Couchbase Lite as a local-only, standalone embedded data store in your iOS, Android, or UWP app. If you want to learn more about Couchbase Mobile, check out the following links.