[英]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.