如何在 ASP.NET Core 3.1 中获取服务实例
How do I get a instance of a service in ASP.NET Core 3.1
我有一个 .NET Core 2.0 的小项目,随着微软宣布不再支持 .NET Core 2.0,我尝试将项目更新到最新版本,此时是 3.1。但是我很难配置依赖注入,需要一些帮助。
为了填充数据库,我需要获取所需的服务,例如 Db 上下文和用户配置,并将其传递给 DbInitialize class,如下所示。我在 Program.cs 配置 Startup.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,您可以通过对现有代码进行较少的更改来实现相同的目的。此 returns 一个 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。
我有一个 .NET Core 2.0 的小项目,随着微软宣布不再支持 .NET Core 2.0,我尝试将项目更新到最新版本,此时是 3.1。但是我很难配置依赖注入,需要一些帮助。
为了填充数据库,我需要获取所需的服务,例如 Db 上下文和用户配置,并将其传递给 DbInitialize class,如下所示。我在 Program.cs 配置 Startup.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,您可以通过对现有代码进行较少的更改来实现相同的目的。此 returns 一个 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。