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


109

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

我越来越

“在类'Program'上调用方法'BuildWebHost'时发生错误。在没有应用程序服务提供商的情况下继续。错误:发生一个或多个错误。(登录名无法打开数据库“ ...”。登录失败。登录用户'...'失败

“无法创建类型为'MyContext'的对象。将'IDesignTimeDbContextFactory'的实现添加到项目中,或者在设计时参见 https://go.microsoft.com/fwlink/?linkid=851728&clcid=0x804

我以前运行的命令是$ dotnet ef migrations add InitialCreate --startup-project "..\Web"(来自具有DBContext的项目/文件夹)。

连接字符串: "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();
}

3
可能问题不在Program.cs中。可能是在Configure方法的末尾使用了一条指令来加载种子数据:DbInitializer.Initialize(上下文);如果您有该说明,请对其进行注释://DbInitializer.Initialize(context); 然后运行迁移说明进行测试。如果出现问题,请继续DbInitializer.cs类。
米格尔·托雷斯

1
您的MyContext类是否在另一个类库项目中?
Orhun

同样的问题,上下文在其他库中。如果id向上下文中添加一个构造函数较少的参数,则迁移工作正常,但存在相同的错误:(在类“ Program”上调用方法“ BuildWebHost”时发生错误。在没有应用程序服务提供者的情况下继续。错误:未设置对象引用到对象的实例。)
iBoonZ

最后解决了吗?
Konrad Viltersten

@MiguelTorresC感谢您的评论。我注释掉了我的“播种方法”,“迁移”又开始起作用了。万分感谢 !!!
阿米特(Amit Philips)

Answers:


123

您可以在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.

资源


2
我得到:找不到配置文件“ appsettings.json”,它不是可选的。物理路径为``C:\ Users \ XXX \ Documents \ Visual Studio 2017 \ Projects \ XXX \ src \ XXX.Api \ bin \ Debug \ netcoreapp2.0 \ appsettings.json''。我的appsettings在C:\ Users \ XXX \ Documents \ Visual Studio 2017 \ Projects \ XXX \ src \ XXX.Api中。
Reft

确保已将appsettings.json文件设置为复制本地,从而解决了找不到该问题的问题
DaImTo

1
此解决方案将对Entity Framework的依赖引入到宿主应用程序中(在我的情况下,这是一个Web项目)。有什么办法可以解决这个问题?我希望我的存储库中包含EF内容,而不是将EF引入Web应用程序中。
Banoona

尽管这是公认的答案,但这样更好:stackoverflow.com/a/52671330/1737395确实,使用--verbose标志运行迁移有很大帮助
barbara.post

73

不需要IDesignTimeDbContextFactory

add-migration initial -verbose

这将揭示下的细节

在类“ Program”上访问IWebHost时发生错误。没有应用程序服务提供商就继续进行。

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

在我的情况下,问题是,具有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'.

3
是的-详细可以帮助您真正发现真正的问题。就我而言,尚未将AddDbContext服务添加到启动中。
sudhakarssd

3
dotnet ef迁移添加了InitialCreate --verbose
barbara.post

4
@tchelidze谢谢您,在我的情况下,我的ApplicationDbContext中没有无参数的构造函数。
蒂亚戈·阿维拉(

1
这是一个绝妙的秘诀,应该是被接受的答案
Avrohom Yisroel

1
非常感谢,这帮助我找到了问题并解决了。在我的情况下,这是“没有为类型'Data.Access.DAL.MainDbContext'定义无参数构造函数。”因此,我只是从构造函数中删除了参数,它就像魔术一样工作!
莎拉

25

解决方案1 ​​:(在99%的情况下找到问题)

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

使用-verboseoption 运行以下命令。

Add-Migration Init -Verbose

-verbose 选项有助于实际发现实际问题,其中包含详细的错误。

解决方案2:

重命名BuildWebHost()CreateWebHostBuilder(),因为Entity Framework Core tools希望找到一种CreateHostBuilder无需运行应用程序即可配置主机的方法。

.NET Core 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 Core 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类型TContextDbContextOptions<TContext>可以从服务容器中进行注入。这要求向您的DbContext类型添加一个构造函数参数accepts DbContextOptions<TContext>

示例:在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)
    { }

}

1
这对我有用。将Program.cs中的BuildWebHost函数从更改public static IWebHostBuilder BuildWebHost(string[] args)public static IWebHost BuildWebHost(string[] args).Build()现在包含在函数中
zola25

1
伙计们,如果您使用的是ASP.NET Core 2.1+,则BuildWebHost方法将具有不同的名称-CreateWebHostBuilder ,因为docs.microsoft.com/en-us/aspnet/core/migration/…因此将CreateWebHostBuilder重命名为BuildWebHost即可找到迁移BuildWebHost并从中获取DbContext。
KEMBL

2
感谢队友,花了2个小时不用配置即可解决IDesignTimeDbContextFactory
Azri Zakaria

3
感谢“ -Verbose”标志。它帮助我找到了异常的根本原因。
Sergey_T

21
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(),因为迁移默认情况下使用此方法。


4
什么。如果您是认真的人,应该在处理此问题的每个页面上刊登此广告。即时成功。谢谢。
Chaim Eliyah,

拯救我的一天!这是非常奇怪的错误。我使用带有预览7的.net core 3.0,并且存在此错误stil
D Todorov


D Todorov只需将BuildWebHost()重命名为CreateHostBuilder()
阿里·巴亚特

1
@WernerCD Cuz Worker使用实现Net Core 3的IHostBuilder的CreateHostBuilder()方法
sherox

11

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

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

“无法创建类型为'MyContext'的对象。将'IDesignTimeDbContextFactory'的实现添加到项目中,或者在设计时参见 https://go.microsoft.com/fwlink/?linkid=851728&clcid=0x804

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


1
谢谢,我也发生了同样的事情。我不得不将启动项目更改为存在Startup / Program类的地方。错误消息是一个坏笑话。
ĽubošČurgó

1
输出消息确实令人沮丧。意外地,我没有选择启动项目。这就是为什么无法创建dbContext的原因。谢谢。
upkit

1
谢谢您,先生...我节省了很多时间
Naveed Khan 19/09/28 '15

7

在AppContext.cs之外的AppContext类中,添加另一个类:

// 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);
    }
}

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

“无法创建类型为'MyContext'的对象。将'IDesignTimeDbContextFactory'的实现添加到项目中,

之后,您将能够添加迁移初始值并通过运行update-database命令执行它。但是,如果在本地SqlServer中还没有数据库的情况下运行这些命令,则会收到类似第一个错误的警告:“一个错误

在类“程序”上调用方法“ BuildWebHost”时发生错误...登录失败。用户“ ...”的登录失败

但这不是错误,因为将创建迁移并可以执行迁移。因此,只需首次忽略此错误,由于Db将存在,因此不会再发生。


4

请确认您有参考

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

5
我正在使用<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />其中包括该参考。我尝试过也包括上述内容,但没有任何变化。
鲁姆(Ruhm)

4

您可以从此讨论中尝试此解决方案,该讨论是受本文启发

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();
}

2
我仍然在:添加'IDesignTimeDbContextFactory <DatabaseContext>'的实现……
Reft

4

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

基本思想是,在将.net核心1转换为2时,所有数据库初始化都应从StartUp.cs移出Program.cs。否则,EF任务将在执行任务时尝试运行数据库init。

“官方迁移文档(https://docs.microsoft.com/en-us/ef/core/miscellaneous/1x-2x-upgrade)中有一个不错的标题为“移动数据库初始化代码”的部分,因此,在像我一样努力解决任何麻烦之前,请确保这不是导致您需要添加IdesignTimeDbContextFactory实现的原因。”


谢谢,这也对我有帮助。
谢尔盖(Sergey)

3

https://docs.microsoft.com/zh-cn/ef/core/miscellaneous/cli/dbcontext-creation

创建新的ASP.NET Core 2.0应用程序时,默认情况下会包含此挂钩。在EF Core和ASP.NET Core的早期版本中,这些工具尝试直接调用Startup.ConfigureServices以获得应用程序的服务提供程序,但是该模式在ASP.NET Core 2.0应用程序中不再正常工作。如果要将ASP.NET Core 1.x应用程序升级到2.0,则可以修改Program类以遵循新模式。

在.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);
        }
    }

3

我遇到了这个问题,并通过“设置”->“ Web应用程序(包括Program.cs)”项目解决了“->设置为启动项目”

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

在Package Manager控制台中

设置为启动项目


谢谢,对我有用的唯一解决方案是将Web项目设置为启动项目,而这正是需要完成的工作。
user3012760

3

如果要避免那些IDesignTimeDbContextFactory问题:只需确保在启动时不使用任何Seed方法。我在启动时使用静态种子方法,这对我造成了此错误。


2

以前,您是在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();
}



2

就我而言,我遇到了问题,因为在Startup.cs文件中调用了一个名为SeedData.EnsurePopulated()的方法。

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);
    }
}

SeedData类的工作是将初始数据添加到数据库表中。它的代码是:

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类的调用即可

// SeedData.EnsurePopulated(app);

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


1

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

  1. API
  2. 服务和仓库,包含上下文模型

最初,API项目被设置为Startup项目。

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

打开解决方案资源管理器>>右键单击上下文项目>>选择“设为启动项目”


1

首先,请确保您已Startup.cs 在以下情况下配置了数据库:在我的情况下,由于未在Startup.cs

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection"), x => x.MigrationsAssembly("<Your Project Assembly name where DBContext class resides>")));

1

使用ASP.NET Core 3.1和EntityFrameWorkCore 3.1.0。仅使用无参数构造函数覆盖上下文类的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);
        }
    }
```

1

我正面临错误

“无法创建类型为'MyContext'的对象。将'IDesignTimeDbContextFactory'的实现添加到项目中,或者在设计时参见https://go.microsoft.com/fwlink/?linkid=851728&clcid=0x804

这就是我解决问题的方式。在解决方案目录中时,运行以下命令

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

这里的Application是我的包含Startup.cs类的启动项目,而Infrastructure是我的包含DbContext类的项目。

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

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

0

自从我引用旧的Microsoft.EntityFrameworkCore.Tools.DotNet以来,我遇到了同样的问题

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

升级到较新版本后,它得到解决


0

在主项目的appsettings.json文件中,我已将“复制到输出目录”设置为“始终复制”,并且可以正常工作。


0

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

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);
        }
    }
}

尽管这可以回答作者的问题,但它缺少一些解释性的文字和文档链接。没有一些短语,原始代码片段不是很有帮助。您可能还会发现如何写一个好的答案很有帮助。请修改您的答案。
hellow 18/09/13

0

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

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

        _config = builder.Build();
    }

0

对我来说,是因为我将Output Type启动项目的项目从更改Console ApplicationClass Library

恢复为Console Application成功。


0

我在具有以下解决方案的解决方案中遇到了这个问题:

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

将Blazor项目设置为启动项目时,出现“无法创建对象...”消息,但如果将MVC项目设置为启动项目,则没有消息。

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

我猜想原因是当Blazor项目是启动项目时,PMC正在从启动项目中确定.NET的版本为Core 3.0,然后尝试使用该版本在.NET Standard 2.0类上运行迁移图书馆并遇到某种冲突。

不管是什么原因,将启动项目更改为针对Core 2.2的MVC项目,而不是Blazor项目,都可以解决此问题。


0

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


0

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

dotnet ef migrations add init -s ../StartUpProjectName

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.