27

We have been trying to run EF Core Migration in .Net Standard 1.6 class library, but it has been failing. But same passes very well in .Net Core 1.1 class library.

Is EF Migration supported in .NET STANDARD?

Tseng
  • 61,549
  • 15
  • 193
  • 205
Abhijeet
  • 13,562
  • 26
  • 94
  • 175

5 Answers5

35

The documentation covers this case as know issue/limitation when the DbContext is placed inside an netstandardx.y Class Library.

Workaround 1 - Use an app as the startup project

If you have an existing .NET Core App or .NET Framework App (including an ASP.NET Core Web Application), you can use it as the startup project. If not, you can create a new one just for use with the .NET Command Line Tools. Specify a startup project that is a "runnable app." Example: console

dotnet ef migrations list --startup-project ../MyConsoleApp/

Workaround 2 - Cross-target a runnable framework

Add an additional target framework to the class library project. This can a version of either .NET Core App or .NET Framework. To make the project a .NET Core App, add the "netcoreapp1.0" framework to project like in the sample below: XML

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netcoreapp1.0;netstandard1.4</TargetFrameworks>
  </PropertyGroup>
</Project>

When targeting .NET Framework, ensure you project targets version 4.5.1 or newer. XML

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net46;netstandard1.4</TargetFrameworks>
  </PropertyGroup>
</Project>
Tseng
  • 61,549
  • 15
  • 193
  • 205
  • 13
    The more I use Entity Framework Core, the more I wonder how it has made it all the way to version 2 in the state that it's in. – Bradley Uffner Jul 13 '17 at 19:04
  • @BradleyUffner: It's due to the way how the context is located and initialized by the tools. EF Core needs a connection string for dependency injection, which needs to be compiled (to make sure its executable) and then launched by the console application. iirc there have been many changes in 2.0 which will fix that. See the [EF Core 2.0: design-time DbContext discovery changes](https://github.com/aspnet/Announcements/issues/258) announcementd – Tseng Jul 13 '17 at 19:33
  • 2
    @BradleyUffner Even with .Net 2.0 I feel the same. Wastage of lot of developer hours with just marketing strategy by MS. Not focusing on making the .Net itself more robust, https://stackoverflow.com/questions/46232820/is-odata-using-microsoft-web-api-really-rest-architecture – Abhijeet Nov 02 '17 at 07:32
  • @BradleyUffner At this level of exp, even Asp.Net Web API seems incomplete https://stackoverflow.com/questions/46319844/group-by-support-in-asp-net-odata – Abhijeet Nov 02 '17 at 07:33
  • Of note to anyone else facing this issue. I tried adding the framework directly on the same TargetFramework propertygroup as suggested, and I received an error. What I ended up doing was to create another your_targetframework and that did the trick. – CesarB Nov 27 '19 at 21:46
16

For you EF Core Package Manager Console Tools users who are seeing the following errors:

Startup project 'MyNetStandardLibrary' 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 Package Manager Console Tools with this project, add an executable project targeting .NET Framework or .NET Core that references this project, and set it as the startup project; or, update this project to cross-target .NET Framework or .NET Core.

OR

Your target project 'MyNetCoreApp' doesn't match your migrations assembly 'MyNetStandardLibrary'. Either change your target project or change your migrations assembly.


The documentation reveals the cause of these errors:

The target project is where any files are added (or in some cases removed). The target project defaults to the Default project selected in Package Manager Console, but can also be specified using the -Project parameter.

The startup project is the one emulated by the tools when executing your project's code. It defaults to one Set as StartUp Project in Solution Explorer. It can also be specified using the -StartupProject parameter.

In a nutshell, you need to set your StartUp Project to a project that has a .NET runtime (.NET Core in this case), then make sure you set your .NET Standard project as the Package Manager Console > Default Project.

Example CLI Solution:

Add-Migration MyMigration -Project MyNetStandardLibrary -StartupProject MyNetCoreApp

Non-CLI Solution:

  1. Right-clicking the .NET Core app in your project
  2. Clicking Set as StartUp Project
  3. Open the Package Manager Console
  4. Select your .NET Standard project from the Default Project dropdown in the Package Manager Console
  5. Run your CLI command (Add-Migration, dotnet ef migrations add, etc.)
Community
  • 1
  • 1
Derek Foulk
  • 1,892
  • 1
  • 19
  • 37
4

I haven't tried with .Net Standard 1.6 but It does work for 2.0.

Microsoft.EntityFrameworkCore.Tools.DotNet needs to be added to each of your class libraries that have a DbContext in them. Right click the project and select Edit *.csproj. Then, add the following:

  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0-preview2-final" />
  </ItemGroup>

You can see a more in-depth tutorial here: EF 7 Migrations with multiple DBContexts

Todd Skelton
  • 6,839
  • 3
  • 36
  • 48
  • Your solution don't work with .NET Core v2.1. If you try to install with NuGet the `Microsoft.EntityFrameworkCore.Tools.DotNet` package to the .NET Standard project where your `DbContext` resides, an error occur saying that it is **only compatible with netcoreapp2.0**. Also, if you manually edit the `.csproj` file and add a reference to `DotNetCliToolReference`, an **obsolete warning appers**. – Cheshire Cat Aug 10 '18 at 15:00
  • 1
    @CheshireCat Yes, that package is obsolete now. You can install the nuget package `Microsoft.EntityframeworkCore.Tools` to get the same capabilities. – Todd Skelton Aug 10 '18 at 15:03
  • @ToddSkeleton Can you please have a look at my new [question](https://stackoverflow.com/questions/51789969/cant-add-entity-framework-core-migrations-to-net-standard-2-0-project), since I still can't make it work... – Cheshire Cat Aug 10 '18 at 15:43
4

All that right but there is a complexity and i would like to give an explanation.

Case: Asp.Net Core, I have a standard library that containing Db-Context. I want to migrate this context but standard library doesn't accepting migration directly, needs a startup project.

Solution: startup project is able to create migration indirectly

Enable-Migrations MyMigration -Project DB-ContextProjectNameThatIsStandartLib -StartupProject CallerExecutableProjectName_LikeMVCWebProjectOrConsole

Add-Migration MyMigration -Project DB-ContextProjectNameThatIsStandartLib -StartupProject CallerExecutableProjectName_LikeMVCWebProjectOrConsole

We will choose Caller Project from the Package Manager Console DropDown but it will create the migration file in the library project. After that don't choose other project from the drop down and run update from the caller project directly without any argument.

Update-Database

try it strange but true

Update: I have upgraded my project Asp.net EntityFrameworkCore 3.1.3 to 3.1.4 and those on up hasnt worked firectly and gave an error :

The EntityFramework package is not installed on project

and this error

Unable to create an object of type 'DomainDbContext'. For the different patterns supported at design time

This is an EntityFramework.Core application! I have installed also EntityFramework to the standart library. But it couldnt understand and restarted V.S. This time it needed to install entityframework to starter MVC (Web) project. I can't do that. I decide to add a new Console Application to solving this requirement. And created below application for this

install-Package Microsoft.Extensions.Configuration
Install-Package Microsoft.Extensions.Configuration.Json
Install-Package Microsoft.Extensions.Configuration.CommandLine
Install-Package Microsoft.Extensions.Configuration.EnvironmentVariables
class Program
{
    public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<DomainDbContext>
    {
        public DomainDbContext CreateDbContext(string[] args)
        {
            IConfigurationRoot configuration = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables()
                //.SetBasePath(Directory.GetCurrentDirectory())
                //.AddJsonFile("appsettings.json")
                .Build();
            var builder = new DbContextOptionsBuilder<DomainDbContext>();
            var connectionString = configuration.GetConnectionString("DefaultConnection");
            builder.UseSqlServer(connectionString);
            return new DomainDbContext(builder.Options);
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
    }
}

This time it has worked correctly! with the above commands again :) cheer

Hamit YILDIRIM
  • 4,224
  • 1
  • 32
  • 35
3

@Tseng, thank you! Here are explicit instructions.

Edit project file:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>
  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
  </ItemGroup>
  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
  </ItemGroup>
</Project>

Then add design factory:

 public class DesignTimeActivitiesDbContextFactory : IDesignTimeDbContextFactory<ActivitiesDbContext>
    {
        public ActivitiesDbContext CreateDbContext(string[] args)
        {
            DbContextOptionsBuilder<ActivitiesDbContext> builder = new DbContextOptionsBuilder<ActivitiesDbContext>();

            var context = new ActivitiesDbContext(
                builder
                .UseSqlServer("Data Source=(local);Initial Catalog=Activities;Integrated Security=False;User ID=user;Password=pw;Connect Timeout=30;Encrypt=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;")
                .Options);

            return context;
        }
    }

Then build.

Then open command prompt, navigate to your projects folder, and run:

dotnet ef migrations add InitialCreate

Now there should be an auto-generated migrations folder. Love it!