Quick Tip: Entity Framework Core Models In Class Library

August 29th, 2016

If you are looking for a way to convert your existing Entity Framework data layer to Core 1.0, you may run into some issues. Today, I provide a workaround thanks to a fellow blogger.

Over this past months, I've been slowly converting my CMS over to ASP.NET MVC/EF/Identity Core 1.0 and implementing pieces as they become more stable.

This weekend, I was wrestling with an issue of generating Entity Framework Entities in an ASP.NET Core 1.0 Class Library.

I wanted to keep my data layer in a separate assembly because, well...you know, it's like an onion.

Thinking I could generate my new entities using the dnx ef scaffold dbcontext technique from before, I tried it.

Just call me Mr. Optimist, but it didn't work.

I was going through everything in my head.

"Ok, do we have everything to generate the entities?"

"Am I missing an assembly?"

Check the project.json

After thinking I didn't have an assembly installed, I looked over the project.json file to see what was missing.

project.json

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0",
      "type": "platform"
    },
    "Microsoft.EntityFrameworkCore.Design": "1.0.0-preview2-final",
    "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
    "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.0",
    "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.Routing.Abstractions": "1.0.0",
    "Microsoft.AspNetCore.Mvc.Abstractions": "1.0.0",
    "System.Collections.Specialized": "4.0.1",
    "Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.0",
    "System.Linq.Queryable": "4.0.1",
    "System.Xml.XmlDocument": "4.0.1"
  },
 
  "tools": {
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
  },
 
  "frameworks": {
    "netcoreapp1.0": {}
  }
}

Nope, nothing looked weird in the project.json.

Next, Try to Generate the Entities...Again

With the project.json in good shape, I tried to generate the entities again by using the command-line in the project directory.

dotnet ef dbcontext scaffold "server=localhost;database=myDatabaseName;Trusted_Connection=true;" Microsoft.EntityFrameworkCore.SqlServer --output-dir Models/EF

After waiting for a couple of seconds, I receive this little message:

error CS5001: Program does not contain a static 'Main' method suitable for an entry point

Umm...you are correct because it's a class library, not an executable.

Ok, that didn't work.

My Last Resort: "Oh Gooooogle?"

In a last ditch effort, I kept asking Ash and Coulson what they thought. They were no help! :-p

So I decided to talk to my other best friend, Google.

After searching for 15 minutes, I found a well-written post by Ben Cull about Entity Framework Core Migrations in Class Library Projects.

It seems this is an issue with EF Migrations Core RTM and it is acknowledged as a problem. They are working on it.

Right now, there is a workaround. You need a static void Main() in an empty Program.cs and place it into your root of the Class Library.

public class Program
{
    // - Taken from http://benjii.me/2016/06/entity-framework-core-migrations-for-class-library-projects/
    //   to make EF work.
    // - Used this to generate EF scaffolding at the command line in the root of the project:
    //     dotnet ef dbcontext scaffold "server=localhost;database=MyDatabaseName;Trusted_Connection=true;" Microsoft.EntityFrameworkCore.SqlServer --output-dir Models/EF
    public static void Main(string[] args)
    {
    }
}

That Was It

Re-run your dotnet ef dbcontext scaffold command from above at the command-line. It will recompile your code and everything should be ok.

One last thing that Ben mentions is that our fake app (the Program.cs) needs to know how to create a DbContext.

Lastly, we need to let our fake app know how to create your DbContext. The tools would normally gather this information from your startup.cs, but since that would be a huge pain to implement, let’s cheat and create an IDbContextFactory instead.

Add the following class to your class library:

public class TemporaryDbContextFactory : IDbContextFactory<PinchContext>
{
    public PinchContext Create(DbContextFactoryOptions options)
    {
        var builder = new DbContextOptionsBuilder<PinchContext>();
        builder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=pinchdb;Trusted_Connection=True;MultipleActiveResultSets=true");
        return new PinchContext(builder.Options);
    }
}

Thanks, Ben (@BenWhoLikesBeer) for getting me back on track with EF Core.