我正在使用 .Net Core 3.1 应用程序和 aspnet 样板模板。 ABP提供了IUnitOfWorkManager。我们可以在构造函数中注入 IUnitOfWorkManager,例如
private readonly IUnitOfWorkManager _unitOfWorkManager;
public MyClass(IUnitOfWorkManager unitOfWorkManager
{
_unitOfWorkManager = unitOfWorkManager
}
public async Task MyMethod()
{
var context = _unitOfWorkManager.Current.GetDbContext<MyDbContext>();
...
}
或者我们可以在方法中直接使用ABP提供的UnitOfWorkManager属性,例如:
public async Task MyMethod()
{
var context = UnitOfWorkManager.Current.GetDbContext<MyDbContext>();
...
}
public IUnitOfWorkManager UnitOfWorkManager
{
get
{
if (_unitOfWorkManager == null)
{
throw new AbpException("Must set UnitOfWorkManager before use it.");
}
return _unitOfWorkManager;
}
set
{
_unitOfWorkManager = value;
}
}
问题是,如果我使用上述任何一种方法,是否需要调用 Dispose() 方法来处置 DBContext?因为我在日志中收到池饥饿异常,并且最常调用的 Api 之一正在使用第二种方法。
对于 ABP UnitOfWorkManager,从文档和命名约定来看,我会说不,您不想显式处理“GetDbContext()”返回的
DbContext
。从我可以在 ABP 框架中找到的有限示例代码来看,这些示例不会包装使用 DbContext
块检索的 using()
实例,因此我完全期望它作为服务定位器运行,公开它在其内部使用的实例。 UoW/存储库包装类。然而,这还没有查看 ABP 框架的源代码(如果有)。这取决于管理者是充当服务定位者还是工厂。工厂模式将创建并返回 DbContext
的新实例,这通常但并不总是意味着消费者应该负责处置。 (至少工厂应该预期消费者可能会也可能不会处置该实例)另一方面,服务定位器模式将管理它所拥有的项目的生命周期范围并提供对这些实例的引用。在这些情况下,您不想显式处置实例,因为该实例在请求该引用的所有代码之间共享。
有一个简单的调试测试,您可以尝试确定 GetDbContext 是工厂还是服务定位器方法:
var context1 = UnitOfWorkManager.Current.GetDbContext<MyDbContext>();
var context2 = UnitOfWorkManager.Current.GetDbContext<MyDbContext>();
bool isSameReference = Object.ReferenceEquals(context1, context2);
如果“isSameReference”返回为
true
那么您不应该处置该实例。如果它是 false
并且 Get 方法返回新实例,那么您很可能应该丢弃。