If your ASP.NET Core project is connecting to your database via entity framework, you can't be unfamiliar with the script: dotnet ef database update. Without executing the script your database is not the latest and this may cause some issues. Traditionally we update the database every time we start our app or publish our app. But we may forget this process and it costs us work. How can we automatically update our database with our application starts?

Before doing this, you need to know that migrating the database automatically is dangerous.

  • Migrations may cause the database to lose data.
  • You may work on an obsolete branch.
  • Migrations may fail.

Migrations may cause your database to lose data. Like your migration may drop some table. Not all environments expect to do that. This may be safe in your development environment but very dangerous in the production environment. This is the main reason why some applications do not migrate automatically.

Now we usually code with git or other version control tools. Switching branches and collaborate with others is more simple. But typically our database doesn't switch branch with your code. If you switched to another branch and just run the application, the migrations may ruin your database and hard for you to recover.

Migrations may fail because of connection reasons or data conflict. If you migrate the database automatically, you will not be warned and this is dangerous because a bigger problem will occur while your service is online.

In one word: Applying migration is a dangerous action. Unless you can ensure everything is fine or you are not suggested to automatically update the database.

To enable it, you need to add the following dependencies to your project:

<PackageReference Include="Polly" Version="7.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.0">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

With the library Polly you can retry a task easily.

And then, copy the following code to your project:

public static IHost MigrateDbContext<TContext>(
    this IHost host)
    where TContext : DbContext
{
    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        var logger = services.GetRequiredService<ILogger<TContext>>();
        var context = services.GetService<TContext>();

        try
        {
            logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}");
            var retry = Policy.Handle<Exception>().WaitAndRetry(new[]
            {
                TimeSpan.FromSeconds(5),
                TimeSpan.FromSeconds(10),
                TimeSpan.FromSeconds(15),
            });

            retry.Execute(() =>
            {
                context.Database.Migrate();
            });
            logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}");
        }
        catch (Exception ex)
        {
            logger.LogError(ex, $"An error occurred while migrating the database used on context {typeof(TContext).Name}");
        }
    }

    return host;
}

It creates an extended method for IHost which allows you to upgrade your database automatically after the application starts. It uses your application's default service provider to create a scope and get your DBContext. And try to migrate the database to the latest status.

If your database is empty or does not exists at all, the script can also create your database automatically.

Finally, use the extend method in your startup process. Like this:

    public static void Main(string[] args)
    {
        CreateHostBuilder(args)
            .Build()
            .MigrateDbContext<YourDbContext>()
            .Run();
    }

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

Try to start your application, and monitor if it can successfully execute the update process.

When you are executing other ef commands like dotnet ef migrations add Test and the script will not be executed. Your database is still the same.