October 2016

Volume 31 Number 10

[Data Points]

Run EF Core on Both .NET Framework and .NET Core

By Julie Lerman

Julie LermanThe technology formerly known as Entity Framework 7 (EF7) was renamed to Entity Framework Core (EF Core) in early 2016. EF Core 1.0.0 introduces some great new capabilities, though overall it does have a smaller feature set than EF6. But this doesn’t mean EF runs only on .NET Core. You can use EF Core in APIs and applications that require the full .NET Framework, as well as those that target only the cross-platform .NET Core. In this column, I’ll walk you through two projects that explore these options. My goal is to alleviate any worries the “Core” moniker might imply: that EF Core only runs on .NET Core. At the same time, I’ll explain the steps involved in creating each solution.

EF Core in Full .NET Projects

I’ll begin with a project that targets the full .NET Framework. Keep in mind that in Visual Studio 2015, the tooling requires that you have Visual Studio 2015 Update 3, as well as the latest Microsoft ASP.NET and Web Tools. At the time of writing this column (August 2016), the best guide for those installations is the documentation at bit.ly/2bte6Gu.

To keep my data access separate from whatever app will be using it, I’ll create it in its own class library. Figure 1 shows that there’s a template that specifically targets a .NET Core class library; but I’m selecting Class Library, the standard option that’s always been available for targeting .NET. The resulting project (Figure 2) is also “normal”—you can see that there are no project.json files or any .NET Core project assets. Everything looks just the way it always has.

Creating a Class Library for a Full .NET API
Figure 1 Creating a Class Library for a Full .NET API

A Plain Old (and Familiar) .NET Class Library
Figure 2 A Plain Old (and Familiar) .NET Class Library

So far, none of this is tied to EF in any way. I could choose EF6 or EF Core at this point, but I’ll add EF Core into the project. As always, I can use either the NuGet Package Manager to find and select EF Core or the Package Manager Console window. I’ll use the console. Remember that the “entityframework” package is for EF6. To get EF Core, you need to install one of the Microsoft.EntityFrameworkCore packages. I’ll use the SqlServer package, which will bring in what EF needs to communicate with SqlServer:

install-package Microsoft.EntityFrameworkCore.SqlServer

Because that package depends on the main Microsoft.EntityFrameworkCore package, as well as the Microsoft.EntityFramework­Core.Relational package, NuGet will install those for me at the same time. And because the EF Core package depends on other packages, they’ll be installed, too. In all, this process adds the three EF Core packages, as well as 23 others from the newer, more composable .NET on which EF Core relies. Rather than fewer large packages, I get more small packages—but only those my software needs. These will all play well with the standard .NET libraries already in the project.

Next, I’ll add in a simple domain class (Samurai.cs) and a DbContext (SamuraiContext.cs) to let EF Core persist my data into a database, as shown in Figure 3. EF Core doesn’t have the magical connection string inference that EF6 has, so I have to let it know what provider I’m using and what connection string. For simplicity, I’ll stick that right in the DbContext’s new virtual method: OnConfiguring. I’ve also created a constructor overload to allow me to pass in the provider and other details as needed. I’ll take advantage of this shortly.

Figure 3 Samurai Class and SamuraiContext DbContext Class

public class Samurai
  {
    public int Id { get; set; }
    public string Name { get; set;}
  }
public class SamuraiContext : DbContext
  {
    public DbSet<Samurai> Samurais { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
      {
        if (optionsBuilder.IsConfigured == false) {
          optionsBuilder.UseSqlServer(
         @"Data Source=(localdb)\\mssqllocaldb;Initial Catalog=EFCoreFullNet;
                       Integrated Security=True;");
        }
        base.OnConfiguring(optionsBuilder);
      }
    }
    public SamuraiContext(DbContextOptions<SamuraiContext> options)
      : base(options) { }
  }

Because I’m using the full .NET, which also means I’m targeting full-blown Windows, I have Windows PowerShell available. And this means I get to use the same migrations commands I’ve always used: add-migration, update-database and so forth. There are some new commands, as well, and you can check out my January 2016 column (msdn.com/magazine/mt614250) to learn all about the EF Core migrations commands. Also, remember I mentioned that packages are smaller and composable? Well, if I want to use migrations, I need to add in the package that contains these commands. As I’m writing this, the tools are still in preview mode so I need to use the -pre parameter. I’ll add that package, then I can add a new migration:

install-package Microsoft.EntityFrameworkCore.Tools –pre
add-migration init

This works as it always has: it creates a new Migrations folder and the migration file, as shown in Figure 4. EF Core did change the way it stores model snapshots, which you can read about in the aforementioned January 2016 column.

EF Core Migrations in My Full .NET Class Library
Figure 4 EF Core Migrations in My Full .NET Class Library

With the migration in place, the update-database command successfully creates the new EFCoreFullNet database for me in SQL Server localdb.

Finally, I’ll add a test project to the solution from the same Unit Test Project template I’ve always used in Visual Studio. I’ll then add a reference to my EFCoreFullNet class library. I don’t need my test project to use the database to make sure EF Core is working, so rather than installing the SqlServer package, I’ll run the following NuGet command against the new test project:

install-package microsoft.EntityFrameworkCore.InMemory

The InMemory provider is a blessing for testing with EF Core. It uses in-memory data to represent the database and the EF cache, and EF Core will interact with the cache in much the same way it works with a database—adding, removing and updating data

Remember that extra constructor I created in the SamuraiContext? The TestEFCoreFullNet tests, shown in Figure 5, take advantage of it. Notice that in the constructor of the test class, I created a DbContext­Options builder for the SamuraiContext and then specified it should use the InMemory provider. Then, in the method when I instantiate SamuraiContext, I pass in those options. The SamuraiContext OnConfiguring method is designed to check to see if the options are already configured. If so, it will use them (in this case, the InMemory provider); otherwise, it will move ahead with setting up to work with SqlServer and the connection string I hardcoded into the method.

Figure 5 Testing with EFCore

using EFCoreFullNet;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
namespace Tests
{
  [TestClass]
  public class TestEFCoreFullNet
  {
    private DbContextOptions<SamuraiContext> _options;
    public TestEFCoreFullNet() {
      var optionsBuilder = new DbContextOptionsBuilder<SamuraiContext>();
      optionsBuilder.UseInMemoryDatabase();
      _options = optionsBuilder.Options;
    }
    [TestMethod]
    public void CanAddAndUpdateSomeData() {
      var samurai = new Samurai { Name = "Julie" };
      using (var context = new SamuraiContext(_options)) {
        context.Add(samurai);
        context.SaveChanges();
      }
      samurai.Name += "San";
      using (var context = new SamuraiContext(_options)) {
        context.Samurais.Update(samurai);
        context.SaveChanges();
      }
      using (var context = new SamuraiContext(_options)) {
        Assert.AreEqual("JulieSan", context.Samurais.FirstOrDefault().Name);
      }
    }
  }
}

This test method takes advantage of some specific EF Core features that don’t exist in EF6. I wrote about these and other change-tracking features in EF Core in my August 2016 Data Points column (msdn.com/magazine/mt767693). For example, after creating the new samurai object, I add it to the context using the DbContext.Add method, letting EF determine to which DbSet it needs to be tied. Then I save that to the data store, in this case some type of list in memory that the InMemory provider is managing. Next, I modify the samurai object, create a new instance of DbContext and use the new EF Core Update command to make sure SaveChanges will update the stored samurai rather than create a new one. Finally, I query the context for that samurai and use an Assert to ensure that the context does indeed return the updated name.

The particular features I’m using are not the point, however. The point is that I’m doing all of this work with EF Core in a “plain old .NET” project in Windows.

EF Core for CoreCLR: Same Code, Different Dependencies

I could stay in Windows and in Visual Studio 2015 Update 3 to next show you how I can use the same EF Core APIs, the same code and the same tests to target the CoreCLR runtime, but that looks too similar to targeting Windows. Therefore, I’ll go to the other extreme and create the CoreCLR variation on my MacBook, explaining the steps as I go through them.

.NET Core doesn’t rely on Windows or its tooling. Besides Visual Studio 2015, I could use … well, I suppose Emacs was the popular non-Visual Studio editor of old. However, there are some cross-platform IDEs I can pick from, not just for writing the code but also to get features like debugging and Git support. For example, in the August 2016 issue of MSDN Magazine, Alessandro Del Sole walked through building an ASP.NET Core Web site using Visual Studio Code (msdn.com/magazine/mt767698). I could see from his screenshots that he was in Windows, but otherwise, the experience is essentially the same on a Mac.

Another cross-platform option is Rider from JetBrains. Rider is designed specifically for C# and the best way to describe it is “ReSharper in its own IDE.”

I’ve already been using Visual Studio Code in Windows and OS X (not just for C#, but also for Node.js) and that’s what I’ll use to show you EF Core in an app built to target CoreCLR. In fact, because I’m building this solution in OS X, targeting CoreCLR is my only option. The array of available APIs for my library is more limited. However, EF Core is the same set of APIs as when I used it in the full .NET library in the first project.

As you’ll see, most of the effort will be in setting up the projects and the dependencies that are specific to targeting CoreCLR. But I can use the same SamuraiContext class to define my EF Core data model and the same CanAddAndUpdateSomeData test method from the previous project to do the same work. The code is the same even though I’m now targeting the more limited runtime and working in an environment that can’t use anything but .NET Core.

Creating a Library Similar to the .NET Class Library

I’ve created a folder to contain both my Library and the Test projects, with subfolders for each project. Inside the Library subfolder, I can call dotnet new to create the Library project. Figure 6 shows that command, along with a confirmation that the project was created. Listing the contents of the folder shows that only two files were created—most important, project.json, which contains the list of required NuGet packages and other relevant project details. The Library.cs file is just an empty class file that I’ll delete.

Creating a New CoreCLR Library with the dotnet Command
Figure 6 Creating a New CoreCLR Library with the dotnet Command

Next, I’ll open this new library project in Visual Studio Code. I can just type “code” at the prompt. Visual Studio Code opens with this as the target folder, automatically recognizes the packages listed in the json file and offers to run dotnet restore to fix up the unresolved dependencies. I happily accept the offer.

The project.json file looks like the code in Figure 7.

Figure 7 The Project.json File

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable"
  },
  "dependencies": {},
  "frameworks": {
    "netstandard1.6": {
      "dependencies": {
        "NETStandard.Library": "1.6.0"
      }
    }
  }
}

Pretty simple. Libraries don’t need all of the ASP.NET Core stuff I’m used to using, just the NETStandard Library. The .NET Standard Library encapsulates what’s common across the various places .NET can now run. From the .NET Standard documentation (bit.ly/2b1JoHJ), “The .NET Standard Library is a formal specification of .NET APIs that are intended to be available on all .NET runtimes.” So this library I’m building can be used with .NET Core and ASP.NET Core and even .NET applications starting with .NET 4.5. You can see a compatibility grid on the documentation page.

My next step is to add EF Core to the project. Keep in mind that because I’m on a Mac, SqlServer isn’t an option. I’ll use the PostgreSQL provider for EF Core instead, which goes in the currently empty dependencies section of project.json:

"dependencies": {
    "Npgsql.EntityFrameworkCore.PostgreSQL": "1.0.0-*"   
  },
  "tools": {
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
  },

As before, I plan to do migrations. Normally, I’d also add a dependency to the Microsoft.EntityFrameworkCore.Tools package that contains the commands, just as I did for the full .NET version of this library. But because of a current limitation with the Preview 2 tooling, I’ll postpone this until a later step in the process. However, I do need to be able to access the commands from this library’s folder, so I add the package into a special “tools” section of project.json, as the preceding code shows.

Restoring the packages pulls in not only these two packages, but their dependencies, as well. If you check in the project.lock.json file that’s created, you can see all of the packages, including Microsoft.EntityFrameworkCore and Microsoft.EntityFramework­Core.Relational—the same packages you saw added into the earlier .NET solution.

Now I’ll just copy in my Samurai.cs and SamuraiContext.cs files. I have to change the OnConfiguring class to use PostgreSQL and its connection string instead of SQL Server. This is what that bit of code now looks like:

optionsBuilder.UseNpgsql(
  "User ID=julie;Password=12345;Host=localhost;Port=5432;Database=EFCoreCoreCLR;
    Pooling=true;");

It should be time to run the migrations, but here you’ll run into a known limitation of the current Preview2 version of the EFCore tools outside of Visual Studio, which is that an executable project is required to find critical assets. So, again, it’s a bit of a pain on first encounter, but not too much in the way of extra effort. Read more about that at bit.ly/2btm4OW.

Creating the Test Project

I’ll go ahead and add in my test project, which I can then use as my executable project for the migrations. Back at the command line, I go to the Oct2016DataPointsMac/Test subfolder I created earlier and run:

dotnet new -t xunittest

In Visual Studio Code, you’ll see the new project.json listed in the Test folder. Because this project will be responsible for making sure the EF command lines can run, you have to add a reference to the EF Core Tools packages into the dependencies. Additionally, the test project needs a reference to the Library, so I’ve also added that into the project.json dependencies. Here’s the dependencies section after these additions:

"dependencies": {
    "System.Runtime.Serialization.Primitives": "4.1.1",
    "xunit": "2.1.0",
    "dotnet-test-xunit": "1.0.0-rc2-192208-24",
    "Library": "1.0.0",
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
  },

Now I can access the EF Core commands from my Library folder. Notice that in Figure 8 the command points to the project in the Test folder with the --startup-project parameter. I’ll use that with each of the migrations commands.

Leveraging an Executable Project to Enable a Library to Use the EF Migrations Commands
Figure 8 Leveraging an Executable Project to Enable a Library to Use the EF Migrations Commands

Running Migrations against the EF Model from the .NET Library

Remember, as I laid out in my column on EFCore migrations, the dotnet ef migrations commands look different from the PowerShell commands, but they lead to the same logic in the migrations API.

First I’ll create the migration with:

dotnet ef --startup-project ../Test migrations add init

This gives the same result as in the .NET solution: a new Migrations folder with the migration and the migration snapshot added.

Now I can create the database with:

dotnet ef --startup-project ../Test database update

I then verified that the PostgreSQL database, tables and relationships got created. There are a number of tools you can use in OS X to do this. On my Mac, I use the JetBrains cross-platform DataGrip as my database IDE.

Running the Tests in CoreCLR

Finally, I copy the TestEFCoreFull­Net class from the earlier solution into my Test folder. Again, I have to make infrastructure changes to use xUnit instead of MS Test: a few namespace changes, removing the TestClass attribute, replacing TestMethod attributes with Fact and replacing Assert.AreEqual with Assert.Equal. Oh and, of course, I rename the class to TestEFCoreCoreClr.

Project.json also needs to know about the InMemory provider, so I add:

"Microsoft.EntityFrameworkCore.InMemory": "1.0.0"

to the dependencies section, as well, then run “dotnet restore” yet again.

My xUnit test project uses the xUnit command-line test runner. So I’m back to my terminal window to run the tests with the command dotnet test. Figure 9 shows the output of running the test, which passed with flying colors—except the command-line test runner doesn’t provide the satisfying green output for passing tests.

xUnit Test Output of the Passing Test
Figure 9 xUnit Test Output of the Passing Test

.NET or CoreCLR: Same APIs, Same Code

So now you can see that the code and assemblies related to EF Core are the same whether you target your software to run solely on Windows with the full .NET Framework at your disposal or on CoreCLR on any of the supported environments (Linux, OS X, Windows). I could’ve done both demonstrations in Visual Studio 2015 on my Windows machine. But I find that focusing the CoreCLR work in an environment that’s completely unavailable to the full .NET Framework is an eye-opening way of demonstrating that the EF APIs and my EF-related code are one and the same in both places. The big differences, and all of the extra work, are only related to the target platforms (.NET vs CoreCLR). You can watch me creating a full ASP.NET Core Web API using EF Core 1.0.0 on my MacBook in the video, “First Look at EF Core 1.0” (bit.ly/PS_EFCoreLook). For an abbreviated and entertaining demo of the same, check out the video of my DotNetFringe session at bit.ly/2ci7q0T.


Julie Lerman is a Microsoft MVP, .NET mentor and consultant who lives in the hills of Vermont. You can find her presenting on data access and other .NET topics at user groups and conferences around the world. She blogs at thedatafarm.com/blog and is the author of “Programming Entity Framework,” as well as a Code First and a DbContext edition, all from O’Reilly Media. Follow her on Twitter: @julielerman and see her Pluralsight courses at juliel.me/PS-Videos.

Thanks to the following Microsoft technical expert for reviewing this article: Jeff Fritz
Jeffrey T. Fritz is a senior program manager in Microsoft’s ASP.NET team working on Web Forms and ASP.Net Core. As a long time web developer with experience in large and small applications across a variety of verticals, he knows how to build for performance and practicality.


Discuss this article in the MSDN Magazine forum