我有一个作用域服务
ScopedA
,我通过 DI 将其注入另一个作用域服务 ScopedB
。Singleton1
:
public class ScopedB
{
ScopedA _scopedA;
Singleton1 _singleton1;
public ServiceB(ScopedA scopedA, Singleton1 singleton1)
{
_scopedA = scopedA;
_singleton1 = singletonA;
}
public async Task DoSomethingAsync()
{
await _singleton1.PerformALongerOperationWichNeedsServiceAAsync(_scopedA);
}
}
Singleton1
在进程的整个生命周期中仅存在一次,而 ScopedA
和 ScopedB
仅在 HTTP 请求(范围内)期间存在。
如果我将实例
_scopedA
传递给 _singleton1
的函数(该函数在后台处理较长时间的某些内容)会发生什么?
假设我的请求已经结束并且
DoSomethingAsync
已经完成,但是单例服务仍在使用_scopedA
做一些事情。
ASP.NET 是否会在函数调用中销毁我的
ScopedA
作用域实例,从而导致某些操作失败?或者像这样的事情可以毫无问题地完成吗?
我知道不建议将
_scopedA
直接注入_singleton1
,因为这会违反范围。
我的例子是否也违反了范围?
如果这是相关的,我正在使用 ASP.NET 6(作为 API),并使用内置 DI 容器 (Microsoft.Extensions.DependencyInjection)。
ASP.NET 是否会在函数调用中销毁我的 ServiceA 作用域实例,从而导致某些操作失败?
单例将能够使用
ServiceA
,除非该类(或其依赖项之一)实现 IDisposable
(或 IAsyncDisposable
)。
当作用域结束时,DI 容器将取消引用
ServiceA
。但由于 ServiceS
仍保留对它的引用,因此 ServiceA
不会被垃圾收集。
但是,如果
ServiceA
或其依赖项之一被处置,它们将在 ServiceS
完成其后台操作之前(或者可以)被处置。当 ObjectDisposedException
尝试访问 ServiceS
时,这可能会导致 ServiceA
被抛出。
尽管当
ServiceA
的对象图不包含任何一次性对象时,这一切都可能起作用,但仍然有很多问题,例如:
ServiceA
可能无法实现 IDisposable
,但通常很难跟踪这是否适用于其所有依赖项。因此,虽然 ServiceS
今天可能能够成功调用 ServiceA
,但稍后将 IDisposable
添加到系统中的另一个类可能会导致应用程序崩溃。ServiceA
已在范围内注册这一事实表明它不是线程安全的。将其传递给单例ServiceS
,后者在不同的线程上访问它(与主操作并行)可能不是一个好主意。不要将作用域依赖项传递给单例,以在其作用域结束后使依赖项保持活动状态,而是让单例从其自己的作用域(在后台操作期间存在)解析其自己的作用域依赖项。