UnitOfWork,存储库数据库连接问题 [英] UnitOfWork, Repository Database Connection Issue
问题描述
I'm using Unity
for Dependency Injection. I implemented generic repository IRepository<T>
and IUnitOfWork
as per direction mentioned here
现在,当我使用构造函数注入访问Service层中的Repository和UnitOfWork时,它将在数据库中添加数据,但从不关闭与数据库的连接.
Now when I access Repository and UnitOfWork in Service layer using constructor injection, it adds the data in database but never closes connection with database.
UnitOfWork实现了IDisposable
,但是由于我无法实现Using
模式,所以一直都没有调用它,因为我知道Repository和UnitOfWork也由其他功能共享.
UnitOfWork implements IDisposable
but that's never called since I'm not able to implement Using
pattern knowing the fact that Repository and UnitOfWork is being shared by other functions also.
container.RegisterType<IRMContext, RMContext>(new PerResolveLifetimeManager());
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerResolveLifetimeManager());
因此,对于提琴手的每个请求,它都会创建与数据库的新连接,并且永远不会关闭,最终达到100个或更多,然后开始失败!
So for each request from fiddler, it creates a new connection to database and never closes, ultimately it reaches to 100 or more and then starts failing!
我在dotnetfiddle中添加了代码- https://dotnetfiddle.net/2K0W48
I have added code here in dotnetfiddle - https://dotnetfiddle.net/2K0W48
根据我的研究进一步更新.如果您查看代码,则其中包含BeginTransaction
方法的IUnitOfWork
实现.如果我不在服务层中使用它,则一切正常.仅维护1个数据库连接.但是,如果使用了该连接,则与该事务关联的连接永远不会关闭,并且会不断增加.
Updating further based on my study. If you look into code, there is IUnitOfWork
implementation having BeginTransaction
method in that. If I donot use that in Service Layer, then everything works fine. Only 1 database connection is maintained. But if that's used, the connection associated with that transaction is never closed and keeps increasing.
推荐答案
在Unity体系结构中,负责处理创建的对象的对象是LifetimeManagers及其实现.在您使用的示例中,是PerResolveLifetimeManager.
In the Unity architecture the object responsible to Dispose the created objects is the LifetimeManagers and its implementations. In the example that you are using, is the PerResolveLifetimeManager.
如果您看到 https://msdn.microsoft.com/en -us/library/ff660872(v = pandp.20).aspx ,您会看到并非每个LifetimeManager都会处置其对象.例如:
If you see at https://msdn.microsoft.com/en-us/library/ff660872(v=pandp.20).aspx, you will see that not every LifetimeManager disposes its objects. For Example:
TransientLifetimeManager :不调用Dispose
ContainerControlledLifetimeManager :处置容器时,它将调用对象的Dispose方法.
HierarchicalLifetimeManager :处置容器时,它将调用对象的Dispose方法.
PerResolveLifetimeManager :不调用Dispose.
PerThreadLifetimeManager :不调用Dispose.
ExternallyControlledLifetimeManager :不调用Dispose.
TransientLifetimeManager: Does not call Dispose
ContainerControlledLifetimeManager: When the container is disposed, it calls the Dispose method of the objects.
HierarchicalLifetimeManager: When the container is disposed, it calls the Dispose method of the objects.
PerResolveLifetimeManager: Does not call Dispose.
PerThreadLifetimeManager: Does not call Dispose.
ExternallyControlledLifetimeManager: Does not call Dispose.
我们可以使用以下代码进行测试:
We can test this with the following code:
[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;
}
}
考虑到这一点,您至少有两个选择:
With this in mind, you have at least two options:
1-使用/创建一个了解执行环境并以某种方式注册自己以处理其创建的所有内容的LifetimeManager,例如PerRequestLifetimeManager(请参阅
1 - Use/Create a LifetimeManager that knows about the execution environment and somehow register itself to dispose everything that it has created, for example PerRequestLifetimeManager (see https://msdn.microsoft.com/en-us/library/microsoft.practices.unity.perrequestlifetimemanager(v=pandp.30).aspx).
PerRequestLifetimeManager将所有创建的实例存储在HttpContext.Current.Items中,并使用一个名为UnityPerRequestHttpModule的关联HttpModule在请求末尾放置所有内容.参见下面的UnityPerRequestHttpModule如何处置其对象.
The PerRequestLifetimeManager stores all created instances in the HttpContext.Current.Items, and use a associated HttpModule called UnityPerRequestHttpModule to dispose everything at the end of the Request. See below how UnityPerRequestHttpModule dispose its objects.
private void OnEndRequest(object sender, EventArgs e)
{
HttpApplication httpApplication = (HttpApplication)sender;
Dictionary<object, object> dictionary = UnityPerRequestHttpModule.GetDictionary(httpApplication.Context);
if (dictionary != null)
{
foreach (IDisposable current in dictionary.Values.OfType<IDisposable>())
{
current.Dispose();
}
}
}
有了这个,第一个可能解决您的问题的方法是:
With this, the first possible solution to your problem is:
var container = new UnityContainer();
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
,并确保注册UnityPerRequestHttpModule(请参阅 https://msdn.microsoft.com/zh-CN/library/dn507440(v = pandp.30).aspx )
and be sure to register the UnityPerRequestHttpModule (see https://msdn.microsoft.com/en-us/library/dn507440(v=pandp.30).aspx)
2-第二个选项是创建一个根容器,向HierarchicalLifetimeManager注册所有临时服务,为每个执行上下文创建一个子容器,并将该子容器放置在执行上下文的末尾.例如:
2 - The second option is to create a root container, register all transient services with HierarchicalLifetimeManager, create a child container for each execution context and dispose this child container at the end of the execution context. For example:
+ 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);
}
}
优点之一是Unity和WebApi之间的集成已经可以与子容器一起使用:
One of the advantages is that the integration between Unity and WebApi already works with child container:
public class UnityDependencyResolver : UnityDependencyScope, IDependencyResolver, IDependencyScope, IDisposable
{
public UnityDependencyResolver(IUnityContainer container) : base(container)
{
}
public IDependencyScope BeginScope()
{
return new UnityDependencyScope(base.Container.CreateChildContainer());
}
}
此解决方案包含一个技巧:如果您忘记在子容器上调用dispose,则会发生两件事:
1-永远不会调用对象的Dispose方法,请参见下面的测试;
This solution contains a trick: if your forget to call the dispose on the child container, two things will happen:
1 - The Dispose method of the objects will never be called, see the test below;
[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!
}
2-将创建内存泄漏.发生这种情况是因为在创建子容器时调用的构造函数将自身插入到父容器的列表中.它会创建一棵树,其中父级指向子级,每个子级都指向父级.该圆圈仅在儿童处置"中被打破.
2 - A memory leak will be created. This happens because the constructor that is called when a child container is created, insert itself in a list in the parent. It creates a tree where the parent points to the children and each child point back to the parent. This circle is only broken in the Child Dispose.
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);
}
...
}
}
这篇关于UnitOfWork,存储库数据库连接问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!