Table of contents
Imagine a software solution that consists of two .NET applications: one desktop application and one web application. Both of these applications should access the same database. Additionally, in the long run, you might want to add new applications which should rely on the same database.
A typical structure of your .NET solution would look as follows: you would build each of these applications independently (i.e. in their own project) and have them reference a shared database project. In the process, you realize that the different application projects have different needs and decide to target the different implementations of .NET accordingly.
The desktop application could, for example, target the .NET Framework since it may only need to run on Windows OS. Whereas the web application could target the .NET Core, since it may need to be deployed across multiple platforms (MacOS, Linux, even docker containers!).
It is at this point when you become aware of the in-depth specifications of the vast Microsoft .NET ecosystem. You cannot reference a project targeting .NET Framework from one targeting .NET Core. Neither does it work the other way around. But what about the database access technology, how does Entity Framework integrate in all this?
And you start wondering: is it even possible?
Is there a way to structure your .NET solution to allow sharing a database project between two (or more!) projects that target .NET Core and .NET Framework respectively?
We found out that it is possible! Keep on reading to figure out how.
For the shared database project, Microsoft is providing us with a database access framework – Entity Framework – which ships in two flavors (Entity Framework 6 and Entity Framework Core). They are both shipped as NuGet packages which makes it easy to integrate them into any project by means of the Visual Studio NuGet Package Manager.
Entity Framework 6 runs on the .NET Framework only and has been first released in 2008, being considered the stable and mature Microsoft ORM solution. At the time of writing, EF6 is still being supported with bug fixes and minor improvements but the current roadmap does not seem to have big plans for upcoming Entity Framework 6.x versions.
On the other hand, Entity Framework Core is a complete rewrite of EF6, having been released in 2016. It now has the full attention of both the EF development team and the .NET developer community. And for a good reason, since it is considered to bring many improvements and new features when compared to EF6. Not only is EF Core designed to be more lightweight and extensible, but it keeps the same syntax as its predecessor, meaning that the developer experience does not change for those used to Entity Framework 6. This article does not cover the differences between the Entity Framework 6 and Entity Framework Core. For an extensive survey, check out the respective documentation.
However, the major EF Core feature that helps us on our mission is the following:
EF Core is supported by both implementations of .NET: .NET Framework and .NET Core.
Let’s see it in action and figure out how we can use EF Core to achieve our desired .NET solution structure.
The frameworks and their versions
At the time of writing, the following are the latest stable versions of the frameworks we are using:
- .NET Framework: 4.6.1
- .NET Core: 2.1
- .NET Standard: 2.0
- Entity Framework Core: 2.2.3
The projects and their dependencies
As outlined in our scenario, we will build a sample solution with 3 projects:
- Database Class Library Project, targeting .NET Standard
- App Project, targeting .NET Framework
- App Project, targeting .NET Core
Both App Projects reference the Database Project which is only possible if the Database project is targeting .NET Standard.
We are now going to consider each of the projects and install their dependencies. We can achieve that using the NuGet Package Manager UI in Visual Studio.
.NET Standard Database Class Library Project
The EF Core APIs are not all packaged into one single assembly, so we can only install dependencies to the ones we need. Firstly, EF Core will need to know which database we will be working with. For the purpose of our demo we will persist the data in SqlServer LocalDB, which comes with Visual Studio. For this we will install the Microsoft.EntityFrameworkCore.SqlServer NuGet package.This package exposes to us a provider that allows us interaction with the database.
Secondly, we want to create and execute migrations so we need access to the migrations commands and logic. These are present in the Microsoft.EntityFrameworkCore.Tools NuGet package.
Note* Referencing the Microsoft.EntityFrameworkCore package is not necessary, since the Core packages will be automatically pulled given the above two packages reference them.
.NET Core App Project
For the .NET Core project, we need to install the following dependency: Microsoft.EntityFrameworkCore.Design.
.NET Framework App Project
For the .NET Framework project, we need to install the following dependencies: Microsoft.EntityFrameworkCore.Design.
The data model
For defining the data model that’s going to be stored in the database, we can create the class Entity.cs and add some basic properties.
The first migration
Our .NET solution structure is defined above and complete with NuGet dependencies and cross-project references. The only thing we need to do is to create the initial migration to get the database up and running.
Whenever we run any migration commands we need to keep in mind the following parameters needed by the Package Manager Console:
- is where the commands will change files
- In our case, we want to have the Database Project as target-project
- needs to be an executable (cannot be a class library project!) and is the one that the tools build and run
- Any of the two Application Projects
Running the add-migration command, using the same syntax as in Entity Framework 6, creates the migrations table and instantiates the database.
And.. that’s it!
Yes, that’s it! The following demonstrates a mock access of the two applications to the shared database.
The database access demo
The following code shows how to use the DbContext to connect to the database, create one entity and read all entities in the database. For the purpose of this demo, both applications are console applications. However, notice that the use of the DbContext does not change across the two applications. How amazing is that?!?
.NET Core App
.NET Framework App
Now the entities added via each of the apps are in the database.
We managed to setup the project dependencies that allow us to have one shared database project, which is referenced by two projects targeting different .NET frameworks. With this solution structure in place, you can now go on and focus on the functionality of your distributed application!