在 .net Core 中使用来自单例范围服务

e22c5c1470abb7cfddaa58d3624d6f68.jpeg

概述:您是否曾经需要将作用域服务注入到单一实例服务中?我经常需要在后台服务中解析作用域内的服务,例如 EF Core。DbContext另一个示例是,当您需要在 ASP.NET Core 中间件中解析作用域服务时。如果你曾经尝试过这个,你可能会遇到一个类似于这个的异常:System.InvalidOperationException: Cannot consume scoped service 'Scoped' from singleton 'Singleton'.今天,我将解释如何解决此问题,以及如何在 ASP.NET Core 中的单例中安全地使用作用域服务。ASP.NET 核心服务寿命ASP.

您是否曾经需要将作用域服务注入到单一实例服务中?

我经常需要在后台服务中解析作用域内的服务,例如 EF Core。DbContext

另一个示例是,当您需要在 ASP.NET Core 中间件中解析作用域服务时。

如果你曾经尝试过这个,你可能会遇到一个类似于这个的异常:

System.InvalidOperationException: Cannot consume scoped service 'Scoped' from singleton 'Singleton'.

今天,我将解释如何解决此问题,以及如何在 ASP.NET Core 中的单例中安全地使用作用域服务。

ASP.NET 核心服务寿命

ASP.NET Core 有三个服务生命周期:

Transient Singleton Scoped

每次从服务容器请求临时服务时,都会创建这些服务。

作用域内服务在作用域的生存期内创建一次。对于 ASP.NET Core 应用程序,将为每个请求创建一个新范围。这是在给定请求中解析作用域内服务的方法。

ASP.NET Core 应用程序还具有用于解析单一实例服务的根。IServiceProvider

那么,如果从单一实例解析作用域内服务引发异常,我们该怎么办?

解决方案 — IServiceScopeFactory

如果要在后台服务中解析作用域内的服务,该怎么办?

您可以创建一个具有其自己的实例的新作用域 ( )。作用域可用于解析作用域内的服务。释放作用域时,也会释放在该作用域内创建的所有一次性服务。IServiceScopeIServiceProviderIServiceProvider

下面是使用 创建新的 .我们正在使用作用域来解析 ,这是一个作用域服务。IServiceScopeFactoryIServiceScopeApplicationDbContext

调用时注册为单例。BackgroundJobAddHostedService

public class BackgroundJob(IServiceScopeFactory serviceScopeFactory)  
    : BackgroundService  
{  
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)  
    {  
        using IServiceScope scope = serviceScopeFactory.CreateScope();  
  
        var dbContext = scope  
            .ServiceProvider  
            .GetRequiredService<ApplicationDbContext>();  
  
        // Do some background processing with the EF database context.  
        await DoWorkAsync(dbContext);  
    }  
}

中间件中的范围服务

如果要在 ASP.NET Core 中间件中使用作用域服务,该怎么办?

中间件在每个应用程序生命周期中构造一次。

如果尝试注入作用域内的服务,则会收到异常:

System.InvalidOperationException: Cannot resolve scoped service 'Scoped' from root provider.

有两种方法可以解决这个问题。

首先,可以使用前面的方法,使用 创建新作用域。你将能够解析作用域内的服务。但是,它们不会与同一请求中的其他作用域服务共享相同的生存期。根据您的要求,这甚至可能是一个问题。IServiceScopeFactory

有更好的方法吗?

中间件允许您在方法中注入作用域服务。注入的服务将使用当前请求的作用域,因此它们将具有与任何其他作用域服务相同的生存期。InvokeAsync

public class ConventionalMiddleware(RequestDelegate next)  
{  
    public async Task InvokeAsync(  
 HttpContext httpContext,  
 IMyScopedService scoped)  
    {  
        scoped.DoSomething();  
  
        await _next(httpContext);  
    }  
}

IServiceScopeFactory 与 IServiceProvider

您可能会看到使用 用于创建作用域而不是 .IServiceProviderIServiceScopeFactory

这两种方法有什么区别?

方法 from 解析实例并调用它:CreateScopeIServiceProviderIServiceScopeFactoryCreateScope()

public static IServiceScope CreateScope(this IServiceProvider provider)  
{  
    return provider.GetRequiredService<IServiceScopeFactory>().CreateScope();  
}

所以,如果你想直接使用 the 来创建一个范围,那很好。IServiceProvider

但是,这是实现预期结果的更直接的方法。IServiceScopeFactory

总结

了解瞬态、作用域和单一实例生存期之间的区别对于管理 ASP.NET Core 应用程序中的依赖关系至关重要。

当您需要从单一实例解析作用域内服务时,它提供了一种解决方案。它允许您创建一个新作用域,您可以使用该作用域来解析作用域内的服务。IServiceScopeFactory

在中间件中,我们可以将作用域服务注入到方法中。这还可以确保服务使用当前请求的范围和生命周期。

如果你喜欢我的文章,请给我一个赞!谢谢

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值