How do I get a instance of a service in ASP.NET Core 3.1

Anduin's answer is good and adding the extension method is a nice way to do it. You can achieve the same with less changes to your existing code if that's what you want by getting the ServiceProvider from the call to Build. This returns an IHost which exposes the IServiceProvider which you previously got through the IWebHost returned by the old BuildWebHost method.

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

        
    using( var scope = host.Services.CreateScope() )
    {
        var services = scope.ServiceProvider;
        try
        {
            var context = services.GetRequiredService<GameStoreContext>();
            var configuration = services.GetRequiredService<IConfiguration>();
            var userManager = services.GetRequiredService<UserManager<IdentityUser>>();
            var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();
            DbInitializer.Initialize(context, configuration, userManager, roleManager).GetAwaiter().GetResult();
        }
        catch( Exception ex )
        {
            var logger = services.GetRequiredService<ILogger<Program>>();
            logger.LogError(ex, "An error occurred while seeding the database.");
        }
    }

        host.Run();
    }

Then you can seed the database and call host.Run afterwards as before.


I understand that you want to get an instance of your DBContext. And execute some code with it. Right here I will give you an example to auto seed the database during ASP.NET Core 3.1 start up. You can try the following code or try the way of soloing your problem.

First, copy the following code to your project:

public static IHost MigrateDbContext<TContext>(this IHost host) where TContext : DbContext
{
    // Create a scope to get scoped services.
    using (var scope = host.Services.CreateScope())
    {
        var services = scope.ServiceProvider;
        var logger = services.GetRequiredService<ILogger<TContext>>();
        // get the service provider and db context.
        var context = services.GetService<TContext>();

        // do something you can customize.
        // For example, I will migrate the database.
        context.Database.Migrate();
    }

    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<WikiDbContext>() // <-- call it here like this.
        .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.

Hope this helps.