1

I've got a Solution with many projects. One of them (Domain) is a .NET Standard 2.0 project where I made my EF Core DbContext implementation for which I want to enable database migrations.

I saw various blogs and Q/A forums where the problem was explained but none of the proposed solutions seem to work for me because of the .NET Core newer version or (probably) for my particular solution configuration.

Solution projects

  • Engine (.NET Core 2.1 Console App)
  • Web API (.NET Core 2.1 Library)
  • Application (.NET Core 2.1 Library)
  • Domain (.NET Standard 2.0 Library)
  • WindowsService (.NET Core 2.1 Console App)

The WindowsService is the Startup project, where an instance of the Engine is created and encapsulated to run as Windows Service or Console application (for debug).

The Engine is the real core application, where an instance of Kestrel self-host Web server is configured as Web API and instantieted. Also other components are instantiated and stay alive (UDP listener, machine watchdog, etc...).

WebAPI has Startup class but no Program class, since all the configuration and the Web server start is done inside Engine.Program.cs class.

Dependencies

  • WindowsService => Engine
  • Engine => WebAPI
  • WebAPI => Application, Domain
  • Application => Domain

The first attempt was to simply launch add-migration Initial from PMC with Domain project as target, but it turns to:

Unable to create an object of type 'MyDbContext'. Add an implementation of 'IDesignTimeDbContextFactory' to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.

Then I followed the proposed solution on this question, but:

  1. add-migration Initial from PMC, after setting My WebAPI (with no Program class) as startup project, turns to:

    It was not possible to find any compatible framework version The specified framework 'Microsoft.NETCore.App', version '2.1.0' was not found.

    • Check application dependencies and target a framework version installed at: C:\Program Files\dotnet\
    • Installing .NET Core prerequisites might help resolve this problem: http://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409
    • The .NET Core framework and SDK can be installed from: https://aka.ms/dotnet-download
    • The following versions are installed: 2.0.5 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] 2.0.6 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] 2.0.7 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] 2.0.9 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] 2.1.2 at [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  2. add-migration Initial from PMC, after adding an additional target framework (netcoreapp2.1) to the Domain library project file, leads me to the same error as the 1st attempt.

  3. add-migration Initial from PMC, after adding a reference to Microsoft.EntityFrameworkCore.SqlServer.Design v1.1.6 always leads to same error as the 1st attempt.

What should I do?

UPDATE

This is the new Domain.csproj file after removing the unecessary libraries references.

<ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.1" />
    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>

All libraries in all projects are up to date.

4
  • Your problem is using Microsoft.EntityFrameworkCore.SqlServer.Design v1.1.6. All of the Microsoft packages should be the same version. 2.1.0 or 2.1.1. Commented Aug 10, 2018 at 16:01
  • Updated my answer to address your Unable to create an object of type 'MyDbContext'. error. Commented Aug 10, 2018 at 16:16
  • 1
    The Design package has been deprecated since 2.0, which is why there's no version available greater than 1.1.6. Remove it from your project. Commented Aug 10, 2018 at 18:46
  • @ChrisPratt The package didn't caused any problem or warning during the installation... and my first attempts was made without the package installed. Anyway, since it didn't solved anything, I removed it. Commented Aug 13, 2018 at 7:15

2 Answers 2

2
  1. Download and install appropriate Runtime and SDK from here - I guess you need .NET Core 2.1.302 at the moment

  2. Microsoft.EntityFrameworkCore.SqlServer.Design is not needed anymore as it's included to SDK. CLI reference in csproj fiels for EntityFrameworkCore is not needed as well.

  3. Make sure you Manage NuGet packages window shows all updated.

  4. Add anywhere in you web project implementation of IDesignTimeDbContextFactory interface - it will be found automatically and used for EF Add-Migration (or dotnet ef... analogues) command in Package Manager Console

    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)\LocalDB;Initial Catalog=DB_name;Integrated Security=True;")
                .Options);
    
            return context;
        }
    }
    

To read the connection string from your appsettings config file you could do the following:

public class DesignTimeActivitiesDbContextFactory : IDesignTimeDbContextFactory<ActivitiesDbContext>
{
    public ActivitiesDbContext CreateDbContext(string[] args)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))
            .AddJsonFile("appsettings.Development.json", optional: false);

        var config = builder.Build();

        var optionsBuilder = new DbContextOptionsBuilder<ActivitiesDbContext>()
            .UseSqlServer(config.GetConnectionString("DefaultConnection"));

        return new ActivitiesDbContext(optionsBuilder.Options);
    }
}

NOTE: in the above code factory will use connection string value defined in appsettings.Development.json file. And connection name is DefaultConnection. In other words, this design time factory is used for the Code First commands like Add-Migration, Update-Database, etc...) and will apply them to the database connection configured for Development environment.

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you, it works! I've just one remark. Since my actual project configuration is not done inside the WebAPI project Startup class, I added the DesignTimeActivitiesDbContextFactory class into that project but I need to manually specify the ConnectionString, while my actual configuration take it from the appsettings.json file using IConfiguration object. Is it someway possible to read it from there too?
@CheshireCat - I have updated the answer - added how you could point factory to use connection string defined in config file. So you can avoid duplicated connection string defined in two places. Hope that helps.
Since I already have a ConfigurationBuilder block with all Json and Env. variables settings, is it a problem in runtime if I instantiate another ConfigurationBuilder on another class?
No, it is not a problem at all. ConfigurationBuilder is just a class to access configuration sources. You can create it when you need.
If you'd like to get connection strings from custom section of your appsettings.json (instead of ConnectionStrings section) check this stackoverflow.com/a/53924899/804385
0

Your csproj file for the class library should contain at least this package. Make sure your versions match for all your Microsoft packages. Either 2.1.0 or 2.1.1 (latest at this time)

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
  </ItemGroup>

</Project>

In the Package Manager Console, set your default project set to the class library where you want the migrations. It's a drop down in the top right of the console window. Also, make sure your start-up project is the project that has the database connection info.

If the start-up project doesn't have an instance of the DbContext you are wanting to scaffold, you will get the error because it doesn't know how to materialize a DbContext. You should have the DbContext registered in your Startup.cs like this:

services.AddDbContext<MyDbContext>(options => options.UseSqlServer(connectionString));

Then, run the command Add-Migration InitialCreate. This will scaffold your migration, it should add a folder to your class library.

After, run Update-Database and it should apply the migration.

If you are still having issues. Make sure you are running the latest SDK. https://www.microsoft.com/net/download

More info can be found in the Docs. https://learn.microsoft.com/en-us/ef/core/managing-schemas/migrations/

1 Comment

"If the start-up project doesn't have an instance of the DbContext you are wanting to scaffold, you will get the error because it doesn't know how to materialize a DbContext" Yes, I was pretty sure that the problem was related to the materialization of DbContext, since my actual configuration (IConfiguration, IServiceProvider, etc.) is done inside another project that has no standard scaffolding, so I was trying to find a workaroung for that. The solution proposed by @DmitryPavlov works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.