10

I did some version upgrade in last months and now I noticed that when I use "remove-migration" to delete migration that I reverted, it's first run my app.

(I noticed that because we do update-database inside startup, so I got to situation where I can't remove migrations, since every time I tried remove migration - it automatically ran the startup which apply the migration to db, then it failed delete it, since it see it in db.)

any idea?

arielorvits
  • 5,235
  • 8
  • 36
  • 61

1 Answers1

27

Update for ASP.NET Core 2.1

In ASP.NET Core 2.1 the methods changed slightly. The general method is similar to the 2.0, just the methods name and return types have been changed.

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

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
    return new WebHostBuilder()
        ...; // Do not call .Build() here
}

ASP.NET Core 2.0

If you are on ASP.NET Core 2.0/EF Core 2.0 then there's been a change to better cover such cases, so that the command line tools can work better.

It's pretty well covered in this announcement.

It boils down to having a static BuildWebHost method which configures the whole application, but doesn't run it.

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

          host.Run();
      }

      // Tools will use this to get application services
      public static IWebHost BuildWebHost(string[] args) =>
          new WebHostBuilder()
              .UseKestrel()
              .UseContentRoot(Directory.GetCurrentDirectory())
              .UseIISIntegration()
              .UseStartup<Startup>()
              .Build();
  }

Also with EF 2.0 it's now recommended to move the migrations to the main method after BuildWebHost has been called. For example

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

        host.Run();
    }

Where Migrate is an extension method:

public static IWebHost Migrate(this IWebHost webhost)
{
    using (var scope = webhost.Services.GetService<IServiceScopeFactory>().CreateScope())
    {
        using (var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>()) 
        {
            dbContext.Database.Migrate();
        }
    }
    return webhost;
}

Now migrations only run, when your application is executed. When you run command line tools, only BuildWebHost will be called and no migrations applied.

Community
  • 1
  • 1
Tseng
  • 61,549
  • 15
  • 193
  • 205
  • 2
    In case you copy pasted the code snippet directly, it's `scope.ServiceProvider.GetRequiredService()` – IvanJazz Sep 22 '17 at 02:15
  • @emp Same, see https://stackoverflow.com/a/38704828/455493. Just the method names changed and return type from `IWebHost` to `IWebHostBuilder` – Tseng Sep 25 '18 at 15:41
  • @Tseng oh I see, need to call it after Build, that also returns an IWebHost. Thanks for the clarification! – emp Sep 25 '18 at 18:03
  • 1
    @emp The new pattern is to call `.Build()` in `Main` method, not in `CreateWebHostBuilder` – Tseng Sep 25 '18 at 18:08
  • If the Migration (or Warmup) method is asynchronous, is it acceptable to call .Result here? – ElFik Dec 04 '18 at 18:48
  • 1
    @ElFik: Since its a console application, you could. though its always better to do `.GetAwaiter().GetResult()` since `.Result` has a different exception behavior (throws `AggregateException` rather than specific exception). But C# 7.0 supports [async Main](https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main/) method, why not just do that, then you can await it w/o any issues – Tseng Dec 04 '18 at 18:51
  • Indeed, I had forgotten about async Main methods. Seems like the right way to go, thanks. – ElFik Dec 04 '18 at 19:21