【问题标题】:Why are my connections not closed even if I explicitly dispose of the DataContext?为什么即使我明确地处理了 DataContext,我的连接也没有关闭?
【发布时间】:2011-02-10 18:47:20
【问题描述】:

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

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

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

我尝试将 Pooling=false 放入我的配置中以查看这是否有任何效果,但它没有。在任何使用池的情况下,我都不希望每次负载都有一个新连接,我希望它能够重用连接。

我已经尝试在析构函数中放置一个断点,以确保 dispose 被命中并且确实如此。那么发生了什么?

一些代码来说明我上面所说的:

控制器:

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来清理非托管资源。

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

【问题讨论】:

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


    【解决方案1】:

    析构函数仅由 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

    【讨论】:

    • 并且实现析构函数。它在这个类中没有任何用途。
    • 啊,你是说 Dispose 不应该在析构函数中调用?
    • 商定的析构函数应该有所不同,很少在 c# 应用程序中使用。
    • @Chris,当 ~MyRepository 被调用时,保证 dc 也被收集。所以在那个阶段是多余的。而且析构函数的成本很高。
    【解决方案2】:

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

    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();
           } 
        }
    }
    

    现在您可以(应该)将 MyController 与 using 子句一起使用:

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

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

    编辑 2:
    这也是正确的(尝试/最终):

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

    如果您不能将其保留在 1 方法中,请尽力在 Closing 事件等中调用 ctl.Dispose() 。

    【讨论】:

    • 啊,谢谢。我只是想知道我的代码是否还需要添加(参考编辑)
    • 最后一点我不太确定。 MVC 生成我的控制器,那么我该如何确保它被正确处理?
    • @Chris,继承时要小心,我注意到您将字段设置为受保护。我不会的。
    • @Henk - 抱歉,我不关注。这些需要受到保护,以便它们可以在继承类中使用。有什么问题?
    • 派生类也需要 IDIsposable 时要小心。
    【解决方案3】:

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

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

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

    【讨论】:

    • 原来的问题已经解决了池化问题(“连接没有被关闭或重用......”)
    • 你能改写一下吗?我不关注?
    • 连接似乎没有返回到池中。无论池是打开还是关闭,新连接总是建立而不是重复使用
    • 通过在终结器中调用 Dispose,在 GC 开始处理终结器队列之前,它不会被 Disposed。 msdn.microsoft.com/en-us/library/66x5fx1b(v=VS.100).aspx
    • 我的意思是,在 Chris 的情况下,Dispose==Close,不管 Pooling 是什么。如果允许 MyController 存活很长时间,则在此期间会建立真正的连接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 2012-06-04
    • 2020-10-13
    相关资源
    最近更新 更多