在 web API 启动 class 中在哪里调用 EF Core Migrate?

Where to call EF Core Migrate in web API startup class?

我正在尝试在 Azure 托管的 Web 中的应用程序启动期间处理数据库迁移 API。但是,无论我尝试把它放在哪里,我都会得到异常:

ObjectDisposedException: Cannot access a disposed object.

我想这是因为我在注入过程的错误部分将上下文迁移调用包装在“using”语句中。但我不确定它应该放在哪里。

我参考了以下文章:

并尝试了以下迁移位置:

public Startup(IConfiguration appSettings)
{
  using var dbContext = new MyContext();
  dbContext.Database.Migrate();
}

这在 MyContext 上产生了 ObjectDisposedException。所以我尝试将其从构造函数中删除并将其添加到服务并将其注入到配置调用中(根据第一篇和第二篇文章):

public Startup(IConfiguration appSettings)
{
}
public void ConfigureServices(IServiceCollection services)
{
  services.AddDbContext<MyContext>();
  [...]
}
public void Configure(IApplicationBuilder app, 
  IWebHostEnvironment env, MyContext dbcontext)
{
  [...]
  dbcontext.Database.Migrate();
}

这还在 MyContext 上产生了 ObjectDisposedException。所以我尝试更改配置方法访问上下文服务的方式(根据第三篇文章):

public Startup(IConfiguration appsettings)
{
}
public void ConfigureServices(IServiceCollection services)
{
  services.AddDbContext<MyContext>();
  [...]
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  [...]
  using var serviceScope = app.ApplicationServices
    .GetRequiredService<IServiceScopeFactory>()
    .CreateScope();
  using var context = serviceScope.ServiceProvider
    .GetService<MyDbContext>();
  context.Database.Migrate();
}

仍然在 MyContext 上产生了 ObjectDisposedException。

如果能帮助我理解我在尝试实施此 EF Core 迁移时做错了什么,我将不胜感激!谢谢!

如果您了解使用具有更改数据库模式权限的连接字符串的安全风险,并且您了解当您的应用程序的多个实例尝试同时迁移数据库时可能出现的问题...

您可以在 Program.Main 中完成。如果您使用的是 Microsoft.Extensions.Hosting,它将如下所示:

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        db.Database.Migrate();
    }

    host.Run();
}

您还可以考虑添加一个管理页面,要求用户在单击按钮迁移数据库之前进行身份验证。

这是针对最新 EF Core 版本的更新解决方案。

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        var migrator = db.Database.GetService<IMigrator>();
        migrator.Migrate();
    }

    host.Run();
}