簡體   English   中英

如何在 ASP.NET Core 3.1 中獲取服務的實例

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

我在 .NET Core 2.0 中有一個小項目,隨着 Microsoft 宣布不再支持 .NET Core 2.0,我嘗試將項目更新到此時的最新版本是 3.1。 但是我很難配置依賴注入,需要一些幫助。

為了填充數據庫,我需要獲取所需的服務,例如 Db 上下文和用戶配置,並將其傳遞給 DbInitialize 類,如下所示。 我在 Startup.cs 配置之前在 Program.cs 中做了這個。

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

但是在 .NET Core 3.1 版本中 BuildWebHost 無法再實例化,所以我無法檢索這樣的服務。

.NET Core 3.1 中新版本的 Program.cs 看起來像這樣

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

有什么方法可以在新框架中實現相同的結果?

OBS:我在一些帖子中讀過人們建議使用 IConfiguration,但我找不到任何示例。

我了解您想要獲取 DBContext 的實例。 並用它執行一些代碼。 在這里,我將舉一個在 ASP.NET Core 3.1 啟動期間自動為數據庫做種的示例。 您可以嘗試以下代碼或嘗試解決問題的方法。

首先,將以下代碼復制到您的項目中:

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

它為 IHost 創建了一個擴展方法,允許您在應用程序啟動后自動升級數據庫。 它使用您應用程序的默認服務提供者來創建范圍並獲取您的DBContext 並嘗試將數據庫遷移到最新狀態。

如果您的數據庫為空或根本不存在,該腳本還可以自動創建您的數據庫。

最后,在啟動過程中使用擴展方法。 像這樣:

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

嘗試啟動您的應用程序,並監控它是否可以成功執行更新過程。

當您執行其他ef命令時,如dotnet ef migrations add Test ,腳本將不會被執行。 你的數據庫還是一樣的。

希望這可以幫助。

Anduin 的回答很好,添加擴展方法是一個很好的方法。 如果您希望通過從對 Build 的調用中獲取 ServiceProvider,您可以通過對現有代碼進行較少更改來實現相同的效果。 這將返回一個 IHost,它公開您之前通過舊 BuildWebHost 方法返回的 IWebHost 獲得的 IServiceProvider。

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

然后你可以播種數據庫並像以前一樣調用 host.Run 。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM