如何在请求后使 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 完成其任务?的主要内容,如果未能解决你的问题,请参考以下文章

如何在某人更改密码后使用户的 JWT 令牌无效

MVC5 中的 IdentityDbContext 和 IdentityDbContext<ApplicationUser> 有啥区别

我们可以在 MFP 上注销后使旧的访问令牌失效吗?

通过加入用户详细信息实体从 IdentityDbContext 获取用户详细信息

如何在特定时间后使函数返回

在 Flutter 中使用 Firebase 电话身份验证超时后使 OTP 无效