Scaffolding an Entity Framework Core database in a project that targets .NETStandard
I've been working on a project recently for storing system configuration data (I know, I know, this is a problem that's been solved a thousand times over!) and after defining the database structure the next thing to do was to create an Entity Framework database context for it. First up is creating the project and solution structure:
md Configuration cd Configuration git init dotnet new sln md Configuration.Database cd Configuration.Database dotnet new classlib cd.. dotnet sln add .\Configuration.Database\
Of course, if you're not using git then swap that command out for one of your choice! I ran this in PowerShell which ends up looking a little bit like this:
Now that the basic project structure is done, I'm going to add a package reference for Microsoft.EntityFrameworkCore.SqlServer, which will let me actually target Entity Framework Core towards my database:
dotnet add .\Configuration.Database\ package Microsoft.EntityFrameworkCore.SqlServer
A few seconds later, NuGet has been interrogated and the package installed which means we can move onto the interesting bit, scaffolding the database!
Scaffolding the database
This is the interesting bit and is achieved by using the dotnet ef dbcontext scaffold command. The command for me is:
dotnet ef dbcontext scaffold "Server=.\;Database=Configuration;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer
This is using two positional arguments for the command, the first to provide the connection string and the second to say what provider should be used. Unfortunately, running this results in the error message:
Startup project 'Configuration.Database.csproj' targets framework '.NETStandard'. There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the Entity Framework Core .NET Command-line Tools with this project, add an executable project targeting .NET Core or .NET Framework that references this project, and set it as the startup project using --startup-project; or, update this project to cross-target .NET Core or .NET Framework. For more information on using the EF Core Tools with .NET Standard projects, see https://go.microsoft.com/fwlink/?linkid=2034781
This is annoying. To solve it the simplest solution is to do exactly as the message states and add another project that can be used as the startup project:
dotnet new console
dotnet add reference ..\Configuration.Database\
dotnet sln add .\Configuration.Database.ConsoleStub\
Now, move back to the folder for the Configuration.Database project and re-run the dotnet ef dbcontext scaffold command, but this time add --startup-project ..\Configuration.Database.ConsoleStub\ to the command:
dotnet ef dbcontext scaffold "Server=.\;Database=Configuration;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer --startup-project ..\Configuration.Database.ConsoleStub\
Alas that's stll not quite enough:
Your startup project 'Configuration.Database.ConsoleStub' doesn't reference Microsoft.EntityFrameworkCore.Design. This package is required for the Entity Framework Core Tools to work. Ensure your startup project is correct, install the package, and try again.
It's easily fixed by running dotnet add ..\Configuration.Database.ConsoleStub\ package Microsoft.EntityFrameworkCore.Design, and then re-running the scaffolding command. If you don't see any error messages, that means it's worked. The last step is to drop down to the solution level and run dotnet build to make sure it all compiles - which it should as all the code is scaffolded! This will pop out a warning of:
ConfigurationContext.cs(30,10): warning CS1030: #warning: 'To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.' [D:\github\Configuration\Configuration.Database\Configuration.Database.csproj]
Pay heed to this and remove the line from ConfigurationContext.cs that contains your connection string!
The things you need to do to scaffold in a class library are:
- Have another project that targets an "actual" framework (I've used a Console App for this), this is the "startup project"
- Ensure that the startup project references the project that the scaffolding will go in
- Ensure that the startup project references Microsoft.EntityFrameworkCore.Design
- Remove the connection string from the generated code - especially important if it uses a username/password pair!