如何在请求后使 IdentityDbContext 保持活动状态,以便服务可以使用 UserManager 完成其任务?
Posted
技术标签:
【中文标题】如何在请求后使 IdentityDbContext 保持活动状态,以便服务可以使用 UserManager 完成其任务?【英文标题】:How do I keep IdentityDbContext alive after a request so that a service can complete its task using UserManager? 【发布时间】:2022-01-12 20:54:08 【问题描述】:我正在从一个页面调用这样的服务:
_ = _importUserService.AddManyUserAsync(ValidatedUsers);
我希望 Page() 返回并让用户/UI 继续前进,同时该服务在后台使用 UserManager 添加许多用户。问题是一旦 Page() 返回并且请求完成,IdentityDbContext 就会关闭并且 UserManager 不再起作用。请求完成后如何让 UserManager 继续工作?
服务使用标准依赖注入:
private readonly UserManager<ApplicationUser> _userManager;
public ImportUserService(UserManager<ApplicationUser> userManager)
_userManager = userManager;
如果我使用 await 而不是 discard 并强制服务在页面加载之前完成,它工作正常;但是,如果用户需要等待 2 分钟才能在页面加载之前导入数千个用户,这将是糟糕的 UX。我的问题是没有创建存储过程并复制 UserManager 正在做的事情,有没有办法在其中使用 UserManager不依赖于请求生命周期的服务?
我的想法是创建一个新的 UserManager 实例,而不是依赖依赖注入中的实例,但到目前为止我还无法让它工作。不确定语法是什么,也找不到在 .net core 3.1 中实际工作的示例
如何在请求后保持 IdentityDbContext 处于活动状态,以便服务可以使用 UserManager 完成其任务? (.Net Core 3.1)
【问题讨论】:
为什么不想await
操作呢?您想知道添加用户实际上是成功还是失败,不是吗?
但是下面的 SO 答案有一个很好的实现:***.com/a/49814520/8941307
如果我等待操作,它不再按要求异步运行。
来自你不能的请求。 DbContext
始终注册为范围服务。因此,当您的网络请求完成时,您的 DbContext
就完成了。您可以通过HostedService
这样做(请参阅第二条评论)。
请阅读Stephen Cleary 的Asynchronous Messaging 博客系列,以更好地了解您应该如何处理这种情况。
【参考方案1】:
来自文档
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio#consuming-a-scoped-service-in-a-background-task
这允许我运行一个后台服务,该服务可以调用使用 UserManager 的服务
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
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>();
)
.ConfigureServices(services =>
services.AddHostedService<ConsumeScopedServiceHostedService>();
);
public class ConsumeScopedServiceHostedService : BackgroundService
private readonly ILogger<ConsumeScopedServiceHostedService> _logger;
public ConsumeScopedServiceHostedService(IServiceProvider services,
ILogger<ConsumeScopedServiceHostedService> logger)
Services = services;
_logger = logger;
public IServiceProvider Services get;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
_logger.LogInformation(
"Consume Scoped Service Hosted Service running.");
await DoWork(stoppingToken);
private async Task DoWork(CancellationToken stoppingToken)
_logger.LogInformation(
"Consume Scoped Service Hosted Service is working.");
using (var scope = Services.CreateScope())
var scopedProcessingService =
scope.ServiceProvider
.GetRequiredService<IScopedProcessingService>();
await scopedProcessingService.DoWork(stoppingToken);
public override async Task StopAsync(CancellationToken stoppingToken)
_logger.LogInformation(
"Consume Scoped Service Hosted Service is stopping.");
await base.StopAsync(stoppingToken);
并且工作在 IScopedProcessingService > DoWork(stoppingToken) 中完成 这意味着 ScopedProcessingService 可以访问与使用我的问题中显示的依赖注入的典型 Web 服务相同的服务。
【讨论】:
以上是关于如何在请求后使 IdentityDbContext 保持活动状态,以便服务可以使用 UserManager 完成其任务?的主要内容,如果未能解决你的问题,请参考以下文章
MVC5 中的 IdentityDbContext 和 IdentityDbContext<ApplicationUser> 有啥区别