.NET Core 依赖注入实例何时处置?
When are .NET Core dependency injected instances disposed?
ASP.NET Core 在 IServiceCollection
上使用扩展方法来设置依赖注入,然后在需要类型时使用适当的方法创建新实例:
AddTransient<T>
- 添加每次请求时都会重新创建的类型。
AddScoped<T>
- 添加为请求范围保留的类型。
AddSingleton<T>
- 在第一次请求时添加类型并保留它。
我有实现 IDisposable
的类型,如果不处理它们会导致问题 - 在每个模式中,Dispose
实际何时被调用?
是否需要添加任何内容(例如异常处理)以确保实例始终被释放?
已解析的对象与其容器具有相同的 life-time/dispose 周期,除非您使用 using
语句或 .Dispose()
方法在代码中手动处理瞬态服务。
在 ASP.NET Core 中,您会得到一个作用域容器,它根据请求进行实例化,并在请求结束时被释放。此时,由该容器创建的作用域和瞬态依赖项也将被释放(如果它们实现了 IDisposable
接口),您也可以在源代码 here 上看到这一点。
public void Dispose()
{
lock (ResolvedServices)
{
if (_disposeCalled)
{
return;
}
_disposeCalled = true;
if (_transientDisposables != null)
{
foreach (var disposable in _transientDisposables)
{
disposable.Dispose();
}
_transientDisposables.Clear();
}
// PERF: We've enumerating the dictionary so that we don't allocate to enumerate.
// .Values allocates a ValueCollection on the heap, enumerating the dictionary allocates
// a struct enumerator
foreach (var entry in ResolvedServices)
{
(entry.Value as IDisposable)?.Dispose();
}
ResolvedServices.Clear();
}
}
单例在父容器被释放时被释放,通常是指应用程序关闭时。
TL;DR:只要您在应用程序启动期间不实例化 scoped/transient 服务(使用 app.ApplicationServices.GetService<T>()
)并且您的服务正确实现 Disposable接口(如 pointed in MSDN),您无需处理任何事情。
父容器在 Configure(IApplicationBuilder app)
方法之外不可用,除非你做了一些时髦的事情让它可以在外面访问(无论如何你不应该这样做)。
当然,我们鼓励尽快释放临时服务,尤其是当它们消耗大量资源时。
ASP.NET Core 在 IServiceCollection
上使用扩展方法来设置依赖注入,然后在需要类型时使用适当的方法创建新实例:
AddTransient<T>
- 添加每次请求时都会重新创建的类型。AddScoped<T>
- 添加为请求范围保留的类型。AddSingleton<T>
- 在第一次请求时添加类型并保留它。
我有实现 IDisposable
的类型,如果不处理它们会导致问题 - 在每个模式中,Dispose
实际何时被调用?
是否需要添加任何内容(例如异常处理)以确保实例始终被释放?
已解析的对象与其容器具有相同的 life-time/dispose 周期,除非您使用 using
语句或 .Dispose()
方法在代码中手动处理瞬态服务。
在 ASP.NET Core 中,您会得到一个作用域容器,它根据请求进行实例化,并在请求结束时被释放。此时,由该容器创建的作用域和瞬态依赖项也将被释放(如果它们实现了 IDisposable
接口),您也可以在源代码 here 上看到这一点。
public void Dispose()
{
lock (ResolvedServices)
{
if (_disposeCalled)
{
return;
}
_disposeCalled = true;
if (_transientDisposables != null)
{
foreach (var disposable in _transientDisposables)
{
disposable.Dispose();
}
_transientDisposables.Clear();
}
// PERF: We've enumerating the dictionary so that we don't allocate to enumerate.
// .Values allocates a ValueCollection on the heap, enumerating the dictionary allocates
// a struct enumerator
foreach (var entry in ResolvedServices)
{
(entry.Value as IDisposable)?.Dispose();
}
ResolvedServices.Clear();
}
}
单例在父容器被释放时被释放,通常是指应用程序关闭时。
TL;DR:只要您在应用程序启动期间不实例化 scoped/transient 服务(使用 app.ApplicationServices.GetService<T>()
)并且您的服务正确实现 Disposable接口(如 pointed in MSDN),您无需处理任何事情。
父容器在 Configure(IApplicationBuilder app)
方法之外不可用,除非你做了一些时髦的事情让它可以在外面访问(无论如何你不应该这样做)。
当然,我们鼓励尽快释放临时服务,尤其是当它们消耗大量资源时。