Creating a shared EF Core database project for use in WPF and Xamarin.Forms apps

Michal Diviš
5 min readFeb 2, 2021

I could never find a good example of using a single EntityFramework Core project in both WPF and Xamarin.Forms apps, with multiple providers. In theory, it’s dead simple, but there are a few little things you have to tinker with to make it work. Here’s how…

The basic idea

The way I go about this is I create a basic database context that only contains the DbSet properties and then make one more context per database provider (PostgreSQL, SQLite in this case) that derives from the basic one. The derived contexts then override their OnConfiguring methods where they set up the connection for their specific provider using a connection string extracted from a helper class.

Why multiple database contexts? In short: migrations. We want to be able to perform migrations for each provider separately since each provider might need the migration to be a bit different from the others. Having multiple contexts allows us to call the Add-Migration command on each of the contexts separately.

Check out the example project

Check out the repository with the complete solution at https://github.com/michaldivis/ocean

Solution structure

Data (.NET Standard class library)

This project will contain the EF Core database context, data models, and some helpers.

Dependencies

Nuget

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Design
  • Microsoft.EntityFrameworkCore.Tools
  • Npgsql.EntityFrameworkCore.PostgreSQL
  • Microsoft.EntityFrameworkCore.Sqlite

Logic (.NET Standard class library)

This project will contain a simple view model that will be shared by the other apps. This will be referencing the Data project.

Dependencies

Projects

  • Data

Nuget

  • Microsoft.EntityFrameworkCore

DesktopApp (.NET Core WPF)

An example WPF app that will use PostgreSQL as the database. This will be referencing the Data and Logic projects.

Dependencies

Projects

  • Data
  • Logic

Nuget

  • Microsoft.EntityFrameworkCore
  • Npgsql.EntityFrameworkCore.PostgreSQL

MobileApp (Xamarin.Forms)

An example mobile app that will use SQLite as the database. This will be referencing the Data and Logic projects.

Dependencies

Projects

  • Data
  • Logic

Nuget

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Sqlite

Used versions

SDK

  • .NET Core 3.1
  • .NET Standard 2.0
  • Xamarin.Forms 4.8

Nuget packages

  • Microsoft.EntityFrameworkCore 3.1.7
  • Npgsql.EntityFrameworkCore.PostgreSQL 3.1.4
  • Microsoft.EntityFrameworkCore.Sqlite 3.1.7

Creating the data project — contexts, models, helpers

Folders

I’ve created two folders in the data project

  • Config — migration configuration values will be here
  • Contexts — db contexts for different platforms will be here
  • Helpers — helper classes for making this usable on multiple platforms will be here
  • Migrations
  • — PostgreSqlMigrations — Migrations for PostgreSQL will be here
  • — SqliteMigrations — Migrations for SQLite will be here
  • Models — data model classes will be here

Models

Let’s say we want to have a database of fish. Here’s a class called Fish.

I’m going to using this class as the example data model.

A way to use different database contexts for different platforms

Since we want to use different databases (PostgreSQL, SQLite) for the two apps, we’ll need a way to make the Data project take in some configuration (wanted database provider, connection string).

For that I’ve created the following items in the “Helpers” folder:

DbProvider.cs

This is an enum that will help us determine what database provider to use

IConnectionString.cs

An abstraction of a connection string, which differs from one provider to another

PostgreSqlConnectionString.cs

A connection string definition for PostgreSQL

SqliteConnectionString.cs

A connection string definition for SQLite

DbHelper.cs

This static class is going to be used to configure the connection from the other projects (DesktopApp, MobileApp)

Database contexts

To use this on multiple platforms, we need to have different database contexts for each platform. However, they need to share the same data sets.

That’s why we’ll create one base context and derive the others from that.

Here’s the base context.

Here’s the PostgreSQL context:

Here’s the SQLite context:

Almost ready, let’s migrate

Now before we use the app, there’s one last step — migrations.

To create an initial (or any other) migration for each database context, we’ll to do the following:

Change the Data project’s target framework to multiple targets to run migrations with it

Go to the Data.csproj and change this:

<TargetFramework>netstandard2.0</TargetFramework>

to this

<TargetFrameworks>netcoreapp2.0;netstandard2.0</TargetFrameworks>

The reason we do that is to be able to run commands using the Data project in the Package Manager Console (which needs a runnable project type to function).

Migrate

Open the Package Manager Console (Tools -> Nuget Package Manager -> Package Manager Console in Visual Studio 2019)

Make sure to have the Data project selected as the default project.

And run the migration command:

SQLite migration command

Add-Migration SqliteMigration001 -Context SqliteOceanDbContext -OutputDir Migrations/SqliteMigrations

PostgreSQL migration command

Add-Migration PostgreSqlMigration001 -Context PostgreSqlOceanDbContext -OutputDir Migrations/PostgreSqlMigrations

After the command finishes, there should be some new files in the corresponding Migrations/ folder.

We’re now ready to use the thing!

Configuring the connection for each platform

MobileApp project

Now let’s configure the database from the mobile project.

Let’s first add a reference to the Data project.

Database file path

We’ll need a way to get some valid database file path for each platform (Android, iOS). Let’s do that.

Create an interface called IDbPathFinder in the MobileApp project

Create an Android implementation of that interface in the MobileApp.Android project

Create an iOS implementation of that interface in the MobileApp.iOS project

Configuring on start

To configure the database connection before we need to use, we’ll make all the call in the App.xaml.cs file.

We’ll add a method called ConfigureDatabase, that will contain the configuration and then call that method from the OnStart method.

The App.xaml.cs file should now look like this:

DesktopApp project

Now let’s configure the database from the desktop project.

Let’s first add a reference to the Data project.

To configure the database connection before we need to use, we’ll make all the call in the App.xaml.cs file.

Add a method called ConfigureDatabase, that will contain the configration.

Then override the OnStartup method and call the ConfigureDatabase from it.

The App.xaml.cs file should now look like this:

Note that in this example I’m hard coding the connection string, which is a terrible idea. Don’t do that!

Let’s try it

Basic view model

To try this, I’ll create a simple class called MainViewModel that will serve as a view model for both the DesktopApp and the MobileApp.

I’ve referenced the Data project and created the following class:

Desktop app view

I’ve added a reference to the Logic project and edited the MainWindow to look like this:

MainWindow.xaml.cs

MainWindow.xaml

Mobile app view

I’ve added a reference to the Logic project and edited the MainPage to look like this:

MainPage.xaml.cs

MainPage.xaml

That’s it

Woohoo! That’s it.

--

--