Home > OS >  EF MigrateAsync() makes the controllers producing 404 Not Found
EF MigrateAsync() makes the controllers producing 404 Not Found

Time:11-01

In my Startup.cs I perform migrations like this. There's some weird issue in the private method I can't explain and it seems to be related to the asynchronous version of the invokation. The following works just as expected (although the asynchornicity in pointless.

public async void Configure(
  IApplicationBuilder app, IWebHostEnvironment env)
{
  ...
  await MigrateDb(app);
  ...
}

private static async Task MigrateDb(IApplicationBuilder app)
{
  using IServiceScope scope = app.ApplicationServices
      .GetService<IServiceScopeFactory>()?.CreateScope();
  if (scope == null)
      throw new OperationCanceledException();

  Context context = scope.ServiceProvider.GetRequiredService<Context>();
  context.Database.Migrate();
}
    

However, when I apply the asynchoronous migration, stuff stop to work. FOr some reason, the controllers are not reachable and I get 404's on every endpoint, including the ping that only returns a fixed string form the service without any contact with the DB.

private static async Task MigrateDb(IApplicationBuilder app)
{
  using ...
  Context context = ...
  await context.Database.MigrateAsync();
}

Googling gave absolutely nothing related. I tried explicitly killing the scope by scope.Dispose();. At the moment I have no idea what to google for more or how to approach the trouble-shooting. It's not a critical production issue - I'm only doing a test (and this part isn't the aim of it). Still, it would be very interesting to understand why this happens.

CodePudding user response:

I am somewhat skeptical about the Configure method. There is difference between async task and async void. There is one answer async/await - when to return a Task vs void? will help to understand that.

Overall async void not handling async of MigrateAsnyc properly and that may leads to problem.

If I have to try another solution then I will program.cs and you can try that. You have to use your own context.

public class Program
    {
        public static async Task Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            //Migrate database
            var scope = host.Services.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<MyContext>();
            await context.Database.MigrateAsync();

            await host.RunAsync();
        }

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