Design patterns UnitOfWork,存储库数据库连接问题

Design patterns UnitOfWork,存储库数据库连接问题,design-patterns,asp.net-web-api2,repository-pattern,unit-of-work,Design Patterns,Asp.net Web Api2,Repository Pattern,Unit Of Work,我使用Unity进行依赖注入。我按照前面提到的方向实现了通用存储库IRepository和IUnitOfWork 现在,当我使用构造函数注入访问服务层中的存储库和UnitOfWork时,它会在数据库中添加数据,但不会关闭与数据库的连接 UnitOfWork实现了IDisposable,但从未调用过它,因为我无法使用模式实现,因为我知道存储库和UnitOfWork也被其他函数共享 container.RegisterType<IRMContext, RMContext>(new Per

我使用
Unity
进行依赖注入。我按照前面提到的方向实现了通用存储库
IRepository
IUnitOfWork

现在,当我使用构造函数注入访问服务层中的存储库和UnitOfWork时,它会在数据库中添加数据,但不会关闭与数据库的连接

UnitOfWork实现了
IDisposable
,但从未调用过它,因为我无法使用
模式实现
,因为我知道存储库和UnitOfWork也被其他函数共享

container.RegisterType<IRMContext, RMContext>(new PerResolveLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerResolveLifetimeManager());
container.RegisterType(新的PerResolveLifetimeManager());
RegisterType(新的PerResolveLifetimeManager());
因此,对于来自fiddler的每个请求,它都会创建一个到数据库的新连接,并且永远不会关闭,最终会达到100个或更多,然后开始失败

我在dotnetfiddle中添加了代码-


根据我的研究进一步更新。如果您查看代码,则其中有
IUnitOfWork
实现具有
BeginTransaction
方法。如果我不在服务层中使用它,那么一切都可以正常工作。仅维护1个数据库连接。但是,如果使用了它,与该事务相关联的连接将永远不会关闭,并且会不断增加。

在Unity体系结构中,负责处理所创建对象的对象是LifetimeManager及其实现。在您使用的示例中,是PerResolveLifetimeManager

如果你看到 ,您将看到并非每个LifetimeManager都会处理其对象。例如:

TransientLifetimeManager:不调用Dispose
ContainerControlled LifetimeManager:当容器被释放时,它调用对象的Dispose方法。
HierarchyCallifeTimeManager:当容器被释放时,它调用对象的Dispose方法。
PerResolveLifetimeManager:不调用Dispose。
PerThreadLifetimeManager:不调用Dispose。
外部控制的LifetimeManager:不调用Dispose

我们可以使用以下代码对此进行测试:

[TestMethod]
public void PerResolveLifetimeManagerDoesNotCallDispose()
{
    var container = new UnityContainer();
    container.RegisterType<IUnitOfWork, UnitOfWork>(new PerResolveLifetimeManager());

    var uow = (UnitOfWork)container.Resolve<IUnitOfWork>();

    Assert.IsFalse(uow.Disposed);

    container.Dispose();

    Assert.IsFalse(uow.Disposed);
}

public interface IUnitOfWork : IDisposable
{
}

public class UnitOfWork : IUnitOfWork
{
    public bool Disposed { get; set; }

    public void Dispose()
    {
        Disposed = true;
    }
}
一个可能的测试是:

[TestMethod]
public void WithChild()
{
    var container = new UnityContainer();
    container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());

    for (int i = 0; i < 10; ++i)
    {
        var child = container.CreateChildContainer();
        var uow = (UnitOfWork)child.Resolve<IUnitOfWork>();

        Assert.IsFalse(uow.Disposed);

        child.Dispose();

        Assert.IsTrue(uow.Disposed);
    }
}
此解决方案包含一个技巧:如果您忘记调用子容器上的dispose,将发生两件事:
1-永远不会调用对象的处置方法,请参见下面的测试

[TestMethod]
public void DoNotForgetToCallTheDispose()
{
    var container = new UnityContainer();
    container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());

    List<UnitOfWork> objects = new List<UnitOfWork>();

    for (int i = 0; i < 10; ++i)
    {
        var child = container.CreateChildContainer();
        var uow = (UnitOfWork)child.Resolve<IUnitOfWork>();
        objects.Add(uow);

        Assert.IsFalse(uow.Disposed);
    }

    Assert.IsTrue(objects.All(x => x.Disposed)); // Will throw!
}

使用一次性的暂时性工作单位。有一个工作单元工厂,在需要时为您提供一个工作单元,以便在不影响其他模块的情况下对其进行处理。@Nkosi,您能解释更多吗?正如我提到的,我已经为unitOfWork实现了一次性,但由于IOC的原因,它从未被调用……我正在使用PerResolveLifetimeManager来管理DBConect和IUnitOfWork。它对请求使用相同的上下文,但一旦请求被服务,它就必须被销毁,对吗?但它没有,对于另一个请求,它会打开一个新的连接,并继续遵循相同的策略。@Nkosi您好,我根据HttpRequest生命周期管理器实现了此功能以解决此问题,但它仍然没有关闭这些连接。这里是链接-这是非常详细和准确的解释,任何人都可以给出。非常感谢。Frederico Lins,如果我的服务是PerResolveLifetimeManager,而IUnitOfWork&DBConext是PerreRequestLifetimeManager,会发生什么情况?(我没有在Request_End中明确删除或调用dispose)如果您的服务是PerResolve,并且您从未调用dispose,那么它们永远不会被直接处理。如果您的IUnitOfWork和DBContext是PerRequest,并且您配置了UnityPerRequestHttpModule,则会自动释放它们,
+ Root
    -- Child 1
        -- Uow1
        -- Svc1
    -- Child 2
        -- Uow1
        -- Svc2
[TestMethod]
public void WithChild()
{
    var container = new UnityContainer();
    container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());

    for (int i = 0; i < 10; ++i)
    {
        var child = container.CreateChildContainer();
        var uow = (UnitOfWork)child.Resolve<IUnitOfWork>();

        Assert.IsFalse(uow.Disposed);

        child.Dispose();

        Assert.IsTrue(uow.Disposed);
    }
}
public class UnityDependencyResolver : UnityDependencyScope, IDependencyResolver, IDependencyScope, IDisposable
{
    public UnityDependencyResolver(IUnityContainer container) : base(container)
    {
    }

    public IDependencyScope BeginScope()
    {
        return new UnityDependencyScope(base.Container.CreateChildContainer());
    }
}
[TestMethod]
public void DoNotForgetToCallTheDispose()
{
    var container = new UnityContainer();
    container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());

    List<UnitOfWork> objects = new List<UnitOfWork>();

    for (int i = 0; i < 10; ++i)
    {
        var child = container.CreateChildContainer();
        var uow = (UnitOfWork)child.Resolve<IUnitOfWork>();
        objects.Add(uow);

        Assert.IsFalse(uow.Disposed);
    }

    Assert.IsTrue(objects.All(x => x.Disposed)); // Will throw!
}
private UnityContainer(UnityContainer parent)
{
    this.parent = parent;
    if (parent != null)
    {
        parent.lifetimeContainer.Add(this);
    }
...
}

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        ...
            if (this.parent != null && this.parent.lifetimeContainer != null)
            {
                this.parent.lifetimeContainer.Remove(this);
            }
        ...
    }
}