即使我明确处理DataContext,为什么我的连接没有关闭?

时间:2010-04-21 19:55:08

标签: c# asp.net-mvc linq-to-sql

我将linq封装到存储库类中的sql调用,该类在我的重载控制器的构造函数中实例化。我的存储库类的构造函数创建数据上下文,以便在页面加载的生命周期中,只使用一个数据上下文。

在我的存储库类的析构函数中,我明确地调用了DataContext的dispose,尽管我不相信这是必要的。

使用性能监视器,如果我观察用户连接数并反复加载页面,则每页加载时数量会增加一次。连接不会被关闭或重复使用(大约20分钟)。

我尝试在我的配置中放置Pooling = false,看看是否有任何效果,但事实并非如此。在使用池的任何情况下,我都不希望每个负载都有新的连接,我希望它可以重用连接。

我已经尝试在析构函数中设置一个断点,以确保处置被击中并确定它已经被击中。那么发生了什么?

一些代码用于说明我上面所说的内容:

控制器:

public class MyController : Controller
{
    protected MyRepository rep;

    public MyController ()
    {
        rep = new MyRepository();
    }
}

存储库:

public class MyRepository
{
    protected MyDataContext dc;

    public MyRepository()
    {
        dc = getDC();
    }

    ~MyRepository()
    {
        if (dc != null)
        {
            //if (dc.Connection.State != System.Data.ConnectionState.Closed)
            //{
            //    dc.Connection.Close();
            //}
            dc.Dispose();
        }
    }

    // etc
}

注意:我向DC添加了一些提示和上下文信息,以便进行审计。这就是为什么我希望每页加载一个连接

更新 在我的存储库和我的控制器类上实现了IDisposable后,我无法找到一种方法来专门调用我的控制器上的Dispose方法,因为MvcHandler在后台创建和销毁控制器。但是我确实发现我的连接正在被关闭。我不知道这是否有效,但我不知道为什么这样做,我做了一些挖掘,发现MSDN引用让我开心:

  

执行完成后,MvcHandler将检查控制器是否实现了IDisposable接口,如果是,则调用控制器上的Dispose来清理非托管资源。

最终更新 经过一个月左右的工作,我现在已经删除了所有这些代码,并在我的公共存储库方法中围绕代码包装“using”语句并将此DC传递给私有方法。这似乎有点浪费和重复,并导致更多的连接被打开和关闭。但我得到了linq到sql缓存,我只能通过重置DC来解决。

3 个答案:

答案 0 :(得分:4)

这里正确的模式(简短但足够的版本)是:

public class MyRepository : IDisposable
{
    ...  // everything except the dtor

    public void Dispose()
    {
        if (dc != null)
        {
            dc.Dispose();
        } 
    }
}

public class MyController : Controller, IDisposable
{
    protected MyRepository rep;

    public MyController ()
    {
        rep = new MyRepository();
    }

    public void Dispose()
    {
       if (rep!= null)
       {
          rep.Dispose();
       } 
    }
}

现在你可以(应该)使用带有using子句的MyController:

using (var ctl = new MyController ())
{
   // use ctl
}

修改
刚注意到它级联到MyController,添加了代码。这显示了非托管资源的间接所有权如何扩散。

编辑2:
这也是正确的(因为这将是一次尝试/最终):

var ctl = GetController ();
using (ctl)
{
   // use ctl
}

如果你不能将它保持为1方法的本地,那么就尽可能在Closing事件中调用ctl.Dispose()等。

答案 1 :(得分:2)

只有GC调用析构函数。你的MyRepository应该实现Dispose模式,并在那里处理dc。

有关详细信息,请参阅此问题。 In C# what is the difference between a destructor and a Finalize method in a class?

MyRepository应该实现IDisposable,如果你在对象的整个生命周期中打开它们,那么任何一次性对象都应该被丢弃。

大多数情况下,当您使用Disposable对象时,应将其包装在using块中

using(var dc = getDC())
{
    //do stuff with the dc
}//the dc will be Disposed here

编辑:链接到c#析构函数的语言指南 http://msdn.microsoft.com/en-us/library/66x5fx1b(v=VS.100).aspx

答案 2 :(得分:0)

我同意一次性作品不正确的事实,Henk HoltermanDarryl Braaten的上述建议非常好,我认为它不能回答你的基本问题。

您的问题的答案是在MyRepository上调用Dispose(假设它是一个DataContext)不会关闭连接。它只返回到池的连接以供下次使用。

This SO Post,解释何时应该担心关闭连接......