0

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.

Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438

1 Answers1

1

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>();
                });
    }
dotnetstep
  • 17,065
  • 5
  • 54
  • 72
  • I would like to emphasize that (to the best of my knowledge), the `async` on `Configure(...)` doesn't seem to be causing the issue. It's when I actually go with the asynchronous version of the migration invokation that the weird poo hits the air blender. And it's even weirder still - Swagger seems to work fine in the same project. It's only **my** controllers that got 404-bye-bye! What the quack?! – Konrad Viltersten Oct 30 '21 at 14:05
  • Have you tried my option because I feel that it is still issue with async void and migrateasync as when async void is there it is not properly return back to that thread and also swagger may be working because it may configure before migrate operation and so whatever after that will configure in pipeline. – dotnetstep Oct 31 '21 at 03:53
  • You also have to provide some more thing from configure method. – dotnetstep Oct 31 '21 at 03:54
  • It's an architectural decision to only do that from the config, so *Startup.cs* is the only allowed spot to horse around (for a variety of reason). Basically, it's decided rather to go synchronously than to change in *Program.cs* so I'm kind of stuck. As for your suggestion, I have previously tried running asynchronous stuff prior to firing up the application and they worked (although I've been instructed to remove it). So I assume that your suggestion for migrations works too (or that it fails in both `Main` and `Startup` classes). Unless you can think of anything else, this is it. :) – Konrad Viltersten Oct 31 '21 at 12:18