Entity Framework Core 2.1 in a Class Library

Entity Framework Core 2.1 in a Class Library

July 11, 2018 0 By Toby Worth

I’ve just started using EF Core 2.1 and have to say I’m enjoying it so far.  As someone with experience with EF back around verison 3 or 4, it was a bit of a nightmare coming from a fully custom SQL backend.  Trying to recreate the relationships in EF meant spending more time editing EDMX files than is strictly healthy.  I certainly didn’t feel it was removing any of the heavy lifting in ORM and basically put me off EF for years.

MS are obviously earning back a lot of trust from the dev community1 and so I thought I’d give it another go.  I haven’t gotten to that level of complexity yet with my current project, but my initial impressions are that it’s a much more mature product with productivity at it’s heart.  As you’d expect, frankly.

One of my requirements from an architectural standpoint was to have the Entity Framework code in its own class library, to better separate concerns.  Pretty much all the examples I’ve seen have EF running side-by-side with the API code as a hosted program with most of the entity framework setup occurring in the Startup.ConfigureServices method.  This is fine for relatively simple use cases, but it’s usually a pain to move it later, so…

Moving Entity Framework Core to a Class Library

It’s actually pretty simple.  You’re able to create entities, contexts and migrations in the same class library without using hosting or any external wrapper to interact with it.

Firstly, create a class library from the CLI. You can obviously do this in Visual Studio, but the CLI is pretty neat and we’re going to be using it a lot more nowadays anyway, so worth getting used to!

[code language=”powershell”]
dotnet new classlib -n App.EFCore
[/code]

Open the project in VS and then right-click to edit the project file, adding the following references:

[code language=”xml”]
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.0" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.1.0-preview1-final" />
</ItemGroup>
[/code]

Create a basic entity for referencing in the context (we’ll build in a moment):

[code language=”csharp”]
using Microsoft.EntityFrameworkCore;

namespace MyApp
{
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
}
}
[/code]

Then, we need to add a class for the context, so create a new class that inherits from the DbContext:

[code language=”csharp”]
using Microsoft.EntityFrameworkCore;

namespace MyApp
{
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> opts) : base(opts) { }

public DbSet<Product> Products { get; set; }
}
}
[/code]

At this point, it’s tempting to try it out, but if you run the migration, you’ll get an error like this:

[code language=”powershell”]
Unable to create an object of type ‘DataContext’. Add an implementation of ‘IDesignTimeDbContextFactory<DataContext>’ to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.
[/code]

At this point, you might have been wondering what kind of black magic may be required to work here (I did, briefly), but it’s nice and simple to set that up. Basically, you just need to add a way for dotnet to instantiate the DataContext via a factory that implements the interface above. This is normally handled in the ConfigureServices method in a Startup class, where the DbContext factory is called via a built-in extension method (services.AddDbContext()).

Since we’re mavericks, we’re going to build our own FROM SCRATCH! Hold on.

[code language=”csharp”]
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace MyApp
{
public class DbContextFactory : IDesignTimeDbContextFactory<DataContext>
{
public DataContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<DataContext>();
builder.UseSqlServer("[your connection string with all the secrets]");

return new DataContext(builder.Options);
}
}
}
[/code]

So simple, right? All we’re doing here is implementing the IDesignTimeDbContextFactory interface so that dotnet can find the ‘CreateDbContext’ method it’s expecting. That method is using the DbContextOptionsBuilder to construct an options object that contains the SQL setup. You can add other options here, like enabling sensitive data logging if you want to debug some data during dev2. Lastly, we return the newly-instantiated DataContext so that the migration tool can get to work writing SQL for you.

Now you can run it:

[code language=”powershell”]
dotnet ef migrations add Initial
[/code]

And you should see the migrations directory appear in the root of your class library project. From there you can run the following to actually build the DB you’ve referenced in the connection string.

[code language=”powershell”]
dotnet ef database udpate
[/code]

I hope this is helpful, let me know if you’ve spotted any errors. I’ll link to a repo with this simple use-case in it (don’t, for the love of cod(e), use this in production!).

Example code here:

EF Core2.1 Class Library

I follow on from this post showing how to secure the connection string secrets using the UserSecrets feature of .Net Core 2.1. It’s a handy way to get on with development without having to set up a key vault and avoids the risk of putting passwords in code!

Securing Passwords and Keys with UserSecrets


1 Except with Edge.  You blew it.  Stop asking.

2 builder.EnableSensitiveDataLogging();