每当我在单例或后台服务中需要瞬态或范围服务时,我都会在子范围中创建它们:
using var serviceScope = _serviceScopeFactory.CreateScope();
var foo = serviceScope.ServiceProvider.GetRequiredService<Foo>();
CreateScope
状态的 API 文档:
退货: 控制作用域生命周期的 IServiceScope。一旦处理完毕,从 IServiceScope.ServiceProvider 解析的任何作用域服务也将被处理。
注意措辞 “任何范围内的服务”。
这是否意味着作用域容器不处理瞬态服务(仅作用域服务)?我一直认为子容器会处理它创建的所有内容,并且只有根容器保留瞬态引用。
(我习惯了 Autofac,它和 .NET DI 之间的一些细微差别有点令人困惑。)
文档这部分中的措辞并不完全正确 - 当范围被处置时,它将处置由范围本身拥有/控制/构造的所有依赖项。这很容易检查:
var services = new ServiceCollection();
services.AddTransient<MyDisposable>();
MyDisposable disposable;
using(var scope = services.BuildServiceProvider().CreateScope())
{
disposable = scope.ServiceProvider.GetRequiredService<MyDisposable>();
}
Console.WriteLine(disposable.Disposed); // true
class MyDisposable : IDisposable
{
public bool Disposed { get; private set; }
public void Dispose()
{
Disposed = true;
}
}
并引用文档:
当您注册实现 IDisposable 的 Transient 服务时,默认情况下 DI 容器将保留这些引用,而不是它们的 Dispose(),直到应用程序停止时容器被释放(如果它们是从容器解析的),或者 直到范围为如果它们是从范围内解决的,则予以处置