升级到 ASP.NET Core 2.0 后无法创建迁移

Unable to create migrations after upgrading to ASP.NET Core 2.0

升级到 ASP.NET Core 2.0 后,我似乎无法再创建迁移了。

我正在

"An error occurred while calling method 'BuildWebHost' on class 'Program'. Continuing without the application service provider. Error: One or more errors occurred. (Cannot open database "..." requested by the login. The login failed. Login failed for user '...'"

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

我之前 运行 的命令是 $ dotnet ef migrations add InitialCreate --startup-project "..\Web"(来自带有 DBContext 的 project/folder)。

连接字符串:"Server=(localdb)\mssqllocaldb;Database=database;Trusted_Connection=True;MultipleActiveResultSets=true"

这是我的Program.cs

 public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
       WebHost.CreateDefaultBuilder(args)
           .UseStartup<Startup>()
           .Build();
}

请确认您有参考资料

<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" />

您可以尝试 this discussion, which was inspired by this post 中的这个解决方案。

public static IWebHost MigrateDatabase(this IWebHost webHost)
{
    using (var scope = webHost.Services.CreateScope())
    {
        var services = scope.ServiceProvider;

        try
        {
            var db = services.GetRequiredService<MyContext>();
            db.Database.Migrate();
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred while migrating the database.");
        }
    }

    return webHost;
}
public static void Main(string[] args)
{
    BuildWebHost(args)
        .MigrateDatabase()
        .Run();
}

之前,您在 Startup.cs 中的 Configure 方法中配置了种子数据。现在建议您仅使用 Configure 方法来设置请求管道。应用程序启动代码属于 Main 方法。

重构的 Main 方法。将以下引用添加到 Program.cs:

使用Microsoft.Extensions.DependencyInjection;

使用MyProject.MyDbContextFolder;

public static void Main(string[] args)
{
    var host = BuildWebHost(args);

    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<MyDbConext>();
            DbInitializer.Initialize(context);
        }
        catch (Exception ex)
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred while seeding the database.");
        }
    }

    host.Run();
}

在 AppContext.cs 除了 AppContext class 添加另一个 class:

// required when local database deleted
public class ToDoContextFactory : IDesignTimeDbContextFactory<AppContext>
{
    public AppContext CreateDbContext(string[] args)
    {
        var builder = new DbContextOptionsBuilder<AppContext>();
          builder.UseSqlServer("Server=localhost;Database=DbName;Trusted_Connection=True;MultipleActiveResultSets=true");
        return new AppContext(builder.Options);
    }
}

这将解决您的第二个问题:

"Unable to create an object of type 'MyContext'. Add an implementation of 'IDesignTimeDbContextFactory' to the project,

之后您将能够 add-migration Initial 并通过 运行 update-database 命令执行。 但是,如果 运行 这些命令在您的本地 SqlServer 中还没有数据库时,您将收到与第一个错误类似的警告:“错误

occurred while calling method 'BuildWebHost' on class 'Program'... The login failed. Login failed for user '...'"

但这不是错误,因为将创建迁移并可以执行。 所以第一次忽略这个错误,以后因为 Db 存在就不会再发生了。

您可以添加一个 class 在您的 Web 项目中实现 IDesignTimeDbContextFactory。

示例代码如下:

public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<CodingBlastDbContext>
{
    public CodingBlastDbContext CreateDbContext(string[] args)
    {
        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();
        var builder = new DbContextOptionsBuilder<CodingBlastDbContext>();
        var connectionString = configuration.GetConnectionString("DefaultConnection");
        builder.UseSqlServer(connectionString);
        return new CodingBlastDbContext(builder.Options);
    }
}

然后,导航到您的数据库项目并从命令行运行执行以下操作:

dotnet ef migrations add InitialMigration -s ../Web/

dotnet ef database update -s ../Web/

-s stands for startup project and ../Web/ is the location of my web/startup project.

resource

2.0 中的 Startup.Configure 中的 ef 播种数据库存在问题...您仍然可以通过此变通方法解决此问题。测试并运行良好

https://garywoodfine.com/how-to-seed-your-ef-core-database/

这篇文章对我真正有帮助:https://elanderson.net/2017/09/unable-to-create-an-object-of-type-applicationdbcontext-add-an-implementation-of-idesigntimedbcontextfactory/

基本思想是,在从 .net core 1 到 2 的转换中,所有数据库初始化都应该移出 StartUp.cs 并移入 Program.cs。否则,EF 任务会尝试 运行 您的数据库在执行任务时会初始化。

"There is a nice section in the official migration docs (https://docs.microsoft.com/en-us/ef/core/miscellaneous/1x-2x-upgrade) titled “Move database initialization code” which I seemed to have missed. So before you head down any rabbit holes like I did make sure this isn’t what is causing your need to add an implementation of IdesignTimeDbContextFactory."

解决方案一:(99%的情况下都能找到问题所在)

Web 应用程序 项目设置为 启动项目

运行 以下命令带有 -verbose 选项。

Add-Migration Init -Verbose

-verbose option helps to actually uncover the real problem, It contains detailed errors.

解决方案 2:

BuildWebHost() 重命名为 CreateWebHostBuilder(),因为 Entity Framework Core tools 希望找到一个 CreateHostBuilder 方法来配置没有 运行 应用程序的主机。

.NET 核心 2.2

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
} 

.NET 核心 3.1

BuildWebHost() 重命名为 CreateHostBuilder()

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

解决方案 3:

确保将 Dbcontext 添加到依赖项注入: AddDbContext<TContext> 将使您的 DbContext 类型 TContext 和相应的 DbContextOptions<TContext> 可用于从服务容器注入。 这需要向接受 DbContextOptions<TContext>.

DbContext 类型添加一个构造函数参数

示例: 在Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
}

AppDbContext代码:

public class AppDbContext: DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
      :base(options)
    { }

}

在我的例子中,我遇到了问题,因为我在 Startup.cs[ 上调用了一个名为 SeedData.EnsurePopulated() 的方法=28=] 文件.

public class Startup
{
    public Startup(IConfiguration configuration) => Configuration = configuration;
    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        //
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseDeveloperExceptionPage();
        app.UseStatusCodePages();
        app.UseStaticFiles();
        app.UseSession();
        app.UseMvc(routes =>
        {
            //
        });

        SeedData.EnsurePopulated(app);
    }
}

SeedDataclass的工作是将初始数据添加到数据库table。它的代码是:

public static void EnsurePopulated(IApplicationBuilder app)
    {
        ApplicationDbContext context = app.ApplicationServices.GetRequiredService<ApplicationDbContext>();
        context.Database.Migrate();
        if (!context.Products.Any())
        {
            context.Products.AddRange(
            new Product
            {
                Name = "Kayak",
                Description = "A boat for one person",
                Category = "Watersports",
                Price = 275
            },
            ....
            );
            context.SaveChanges();
        }
    }

解决方案

在进行迁移之前,只需在 Startup.cs 文件中注释掉 SeedData class 的调用。

// SeedData.EnsurePopulated(app);

这解决了我的问题,希望您的问题也能以同样的方式解决。

我遇到了同样的问题,因为我指的是旧的- Microsoft.EntityFrameworkCore.Tools.DotNet

<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />

升级到较新版本后问题得到解决

就我而言,问题的原因是多个启动项目。我的解决方案中有三个项目:Mvc、Api 和 Dal。 Dal 项目中的 DbContext 和迁移。

我配置了多个启动项目。当我单击开始时,Mvc 和 Api 项目都是 运行。但在这种情况下,我收到了这个错误。

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

在将 Mvc 设置为唯一的启动项目并在包管理器控制台中选择 Dal 后,我可以成功添加迁移。

在主项目的 appsettings.json 文件中,我将 'Copy to Output directory' 设置为 "Copy always" 并且有效。

来自

https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dbcontext-creation

When you create a new ASP.NET Core 2.0 application, this hook is included by default. In previous versions of EF Core and ASP.NET Core, the tools try to invoke Startup.ConfigureServices directly in order to obtain the application's service provider, but this pattern no longer works correctly in ASP.NET Core 2.0 applications. If you are upgrading an ASP.NET Core 1.x application to 2.0, you can modify your Program class to follow the new pattern.

在 .Net Core 中添加工厂 2.x

public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
    {
        public BloggingContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
            optionsBuilder.UseSqlite("Data Source=blog.db");

            return new BloggingContext(optionsBuilder.Options);
        }
    }

.net 核心控制台应用程序的示例数据库上下文 class

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using System.IO;

namespace EmailServerConsole.Data
{
    public class EmailDBContext : DbContext
    {
        public EmailDBContext(DbContextOptions<EmailDBContext> options) : base(options) { }
        public DbSet<EmailQueue> EmailsQueue { get; set; }
    }

    public class ApplicationContextDbFactory : IDesignTimeDbContextFactory<EmailDBContext>
    {
        EmailDBContext IDesignTimeDbContextFactory<EmailDBContext>.CreateDbContext(string[] args)
        {
            IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();
            var builder = new DbContextOptionsBuilder<EmailDBContext>();
            var connectionString = configuration.GetConnectionString("connection_string");
            builder.UseSqlServer(connectionString);
            return new EmailDBContext(builder.Options);
        }
    }
}

不需要IDesignTimeDbContextFactory.

运行

add-migration initial -verbose

这将显示

下的详细信息

An error occurred while accessing the IWebHost on class 'Program'. Continuing without the application service provider.

警告,这是问题的根本原因。

在我的例子中,问题是,有 ApplicationRole : IdentityRole<int> 并调用 services.AddIdentity<ApplicationUser, IdentityRole>() 导致以下错误

System.ArgumentException: GenericArguments[1], 'Microsoft.AspNetCore.Identity.IdentityRole', 
on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`9[TUser,TRole,TContext,
TKey,TUserClaim,TUserRole,TUserLogin,TUserToken,TRoleClaim]' violates the constraint of type 'TRole'.
---> System.TypeLoadException: GenericArguments[1], 'Microsoft.AspNetCore.Identity.IdentityRole', 
on 'Microsoft.AspNetCore.Identity.UserStoreBase`8[TUser,TRole,TKey,TUserClaim,
TUserRole,TUserLogin,TUserToken,TRoleClaim]' violates the constraint of type parameter 'TRole'.

我遇到了这个问题并通过设置 -> Web 应用程序(包含 Program.cs)项目解决了 -> "Set as Startup Project"

然后 运行 -> add-migration initial -verbose

在程序包管理器控制台中

Set as Startup Project

我有同样的问题。刚刚将 ap.jason 更改为 application.jason 并解决了问题

如果您想避免那些 IDesignTimeDbContextFactory 事情:只需确保您在启动时不使用任何 Seed 方法。我在启动时使用了静态种子方法,它导致了我这个错误。

您还可以在启动 class 构造函数中使用将 json 文件(连接字符串所在的位置)添加到配置中。示例:

    IConfigurationRoot _config;
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json");

        _config = builder.Build();
    }
public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
    }
}

只需将 BuildWebHost() 重命名为 CreateWebHostBuilder(),因为迁移默认使用此方法。

对我来说,这是因为我将启动项目的 Output TypeConsole Application 更改为 Class Library

恢复到 Console Application 成功了。

我在一个解决方案中遇到了这个问题:

  • 一个 .NET Core 2.2 MVC 项目
  • 一个 .NET Core 3.0 Blazor 项目
  • .NET Standard 2.0 中的数据库上下文 class 库项目

当 Blazor 项目设置为启动项目时我收到 "unable to create an object..." 消息,但如果 MVC 项目设置为启动项目则不会。

这让我很困惑,因为在包管理器控制台(这是我创建迁移的地方)我将默认项目设置为实际包含数据库上下文的 C# class 库,并且我还在对 add-migration add-migration MigrationName -context ContextName 的调用中指定了数据库上下文,因此 Visual Studio 关心当前设置的启动项目似乎很奇怪。

我猜原因是,当 Blazor 项目是启动项目时,PMC 从启动项目中确定 .NET 的版本为 Core 3.0,然后尝试将其用于 运行 .NET Standard 2.0 class 库上的迁移并遇到某种冲突。

无论是什么原因,将启动项目更改为针对 Core 2.2 的 MVC 项目,而不是 Blazor 项目,都解决了问题

我运行遇到同样的问题。我在解决方案中有两个项目。

  1. API
  2. Services and repo, which hold context models

最初,API 项目被设置为启动项目。

我将 启动项目更改为包含上下文 类 的项目。 如果您使用 Visual Studio 您可以通过以下方式将项目设置为启动项目:

open solution explorer >> right-click on context project >> select Set as Startup project

首先确保您已经在 Startup.cs 中配置了数据库 就我而言,我收到此错误是因为我没有在 Startup.cs

中指定以下内容
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection"), x => x.MigrationsAssembly("<Your Project Assembly name where DBContext class resides>")));

对我来说,问题是我 运行 错误项目中的迁移命令。 运行 项目中包含 Startup.cs 而不是包含 DbContext 的项目中的命令让我克服了这个特殊问题。

使用 ASP.NET Core 3.1 和 EntityFrameWorkCore 3.1.0。仅使用无参数构造函数覆盖上下文 class 的 OnConfiguring

```protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            IConfigurationRoot configuration = new ConfigurationBuilder()
               .SetBasePath(Directory.GetCurrentDirectory())
               .AddJsonFile("appsettings.json")
               .Build();
            var connectionString = configuration.GetConnectionString("LibraryConnection");
            optionsBuilder.UseSqlServer(connectionString);
        }
    }
```

就我而言,在 init 中设置 StartUp 项目很有帮助。您可以通过执行

dotnet ef migrations add init -s ../StartUpProjectName

我遇到了错误

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

我的问题就这样解决了。 运行 在您的解决方案目录中执行以下命令

 dotnet ef migrations add InitialMigration --project "Blog.Infrastructure" --startup-project "Blog.Appication"

这里的 Application 是我的启动项目,包含 Startup.cs class & Infrastructure 是我的项目,包含 DbContext class.

然后 运行 使用相同的结构进行更新。

dotnet ef database update --project "Blog.Infrastructure" --startup-project "Blog.Application"

Manzur Alahi 是对的!我正在尝试通过 JetBrains 学习 Rider,当我尝试在 Cmd、PowerShell 等中使用 dotnet-ef migrations add ... 时遇到了同样的错误,但是当我使用 Visual Studio IDE 时我没有没问题。

我修复了错误:

dotnet ef migrations add InitialMigration --project "Domain.Entities" --startup-project "WebApi"

然后更新数据库

dotnet ef database update --project "Domain.Entities" --startup-project "WebApi"

正如Manzur Alahi所说。

如果上下文 class 在另一个 class 库项目中并且发生此错误,请将命令行默认项目更改为上下文项目并将解决方案启动项目设置为主要 API /ASP.net核心项目(就是你的DI容器在那里),然后重新运行命令 似乎 ef 核心工具包中报告了这个错误 https://github.com/dotnet/efcore/issues/23957 and https://github.com/dotnet/efcore/issues/23853