Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a small project in .NET Core 2.0 and as Microsoft announced that would no longer support .NET Core 2.0 I tried to update the project to the latest version at this time is 3.1. But I had a hard time configuring the Dependency Injection and need some help.

In order to populate the database, I need to get required services such as Db Context and user configuration and pass this on to DbInitialize class as shown below. I did this in Program.cs before Startup.cs configuration.

public class Program {
        public static void Main(string[] args)
        {

            var host = BuildWebHost(args);

            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();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .Build();
    }

But in the .NET Core 3.1 version BuildWebHost can no longer be instantiated so I was unable to retrieve services like this.

The new version of Program.cs in .NET Core 3.1 looks like this

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

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

There is any way that I can achieve the same result in the new Framework?

OBS: I have read in some posts people advising to use IConfiguration but I couldn't find any example.

like image 322
Leonardo De Lima Ferreira Avatar asked Jan 16 '20 17:01

Leonardo De Lima Ferreira


1 Answers

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.

like image 200
Anduin Avatar answered Sep 21 '22 15:09

Anduin