C# 池中的连接正在耗尽

C# 池中的连接正在耗尽,c#,sql-server,ado.net,connection-pooling,webforms,C#,Sql Server,Ado.net,Connection Pooling,Webforms,我有一个web表单应用程序,可以在GridView中显示记录列表,通过选中多个复选框,可以批量删除记录。代码本身很简单: protected void btnDelete_Click(object sender, EventArgs e) { int i = 0; try { foreach (GridViewRow row in GridView1.Rows) { CheckBox cb = (CheckBox)r

我有一个web表单应用程序,可以在GridView中显示记录列表,通过选中多个复选框,可以批量删除记录。代码本身很简单:

protected void btnDelete_Click(object sender, EventArgs e)
{
    int i = 0;
    try
    {
        foreach (GridViewRow row in GridView1.Rows)
        {
            CheckBox cb = (CheckBox)row.FindControl("ID");
            if (cb != null && cb.Checked)
            {
                int profileID = Convert.ToInt32(GridView1.DataKeys[row.RowIndex].Value);
                Profile profile = new Profile(profileID); //instantiate profile
                profile.Delete(); //call delete method
                i++;
            }
        }
        if (i > 0)
        {
            //report success to UI
        }
    }
    catch (Exception ex)
    {
        //report error to UI
    }
}
在概要文件构造函数中,它通过打开连接、打开数据读取器,然后设置对象的属性来对对象进行水合物化。我对在代码中使用块非常谨慎,因此每个db连接看起来都是这样的:

using (SQLHelper db = new SQLHelper())
{
    db.AddParameterToSQLCommand("@ProfileID", SqlDbType.Int);
    db.SetSQLCommandParameterValue("@ProfileID", id);

    using (SqlDataReader dr = db.GetReaderByCmd("up_GetProfile"))
    {
        if (dr.Read())
        {
            _profileID = id;
            if (!dr.IsDBNull(0))
                ProfileName = dr.GetString(0);
            //... and so on
            return true;
        }
        else
        {
            return false;
        }
    }
}
public void Dispose()
{
    try
    {
        //Clean Up Connection Object
        if (mobj_SqlConnection != null)
        {
            if (mobj_SqlConnection.State != ConnectionState.Closed)
            {
                mobj_SqlConnection.Close();
            }
            mobj_SqlConnection.Dispose();
        }

        //Clean Up Command Object
        if (mobj_SqlCommand != null)
        {
            mobj_SqlCommand.Dispose();
        }
    }

    catch (Exception ex)
    {
        throw new Exception("Error disposing data class." + Environment.NewLine + ex.Message);
    }
}
datareader实现IDisPoble,就像我的助手类一样,析构函数如下所示:

using (SQLHelper db = new SQLHelper())
{
    db.AddParameterToSQLCommand("@ProfileID", SqlDbType.Int);
    db.SetSQLCommandParameterValue("@ProfileID", id);

    using (SqlDataReader dr = db.GetReaderByCmd("up_GetProfile"))
    {
        if (dr.Read())
        {
            _profileID = id;
            if (!dr.IsDBNull(0))
                ProfileName = dr.GetString(0);
            //... and so on
            return true;
        }
        else
        {
            return false;
        }
    }
}
public void Dispose()
{
    try
    {
        //Clean Up Connection Object
        if (mobj_SqlConnection != null)
        {
            if (mobj_SqlConnection.State != ConnectionState.Closed)
            {
                mobj_SqlConnection.Close();
            }
            mobj_SqlConnection.Dispose();
        }

        //Clean Up Command Object
        if (mobj_SqlCommand != null)
        {
            mobj_SqlCommand.Dispose();
        }
    }

    catch (Exception ex)
    {
        throw new Exception("Error disposing data class." + Environment.NewLine + ex.Message);
    }
}
当我逐步浏览我的代码时,我看到连接总是正确地打开和关闭,我的堆栈深度从未超过五到六次调用。我没有遇到任何递归问题。我已经确认,我所有的数据访问代码都正确地包装在使用块中,但我的连接没有被释放回池中。相反,我得到了以下错误:

Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
这发生在一个专用的应用程序池中,单个用户对10多个配置文件执行删除操作。 看起来我做的每件事都是正确的,但是我不知道为什么连接没有被释放回池中。执行线程最多只能打开两个连接,这两个连接都应该和do!当它们超出范围时进行处置


很明显我做错了什么,但我一辈子都搞不清楚是什么

如果我没记错,SqlHelper dispose不会自动关闭连接。您需要显式地关闭它


我们总是在try/finally中使用SqlHelper,在finally中显式地调用close。

根据我的评论,我将转换为答案

看起来您正试图在命令对象之前关闭连接对象,并且由于命令对象引用了一个连接,因此可能会使该连接保持活动状态

试着换一下:

//Clean Up Command Object
if (mobj_SqlCommand != null)
{
  mobj_SqlCommand.Dispose();
}

if (mobj_SqlConnection != null)
{
  if (mobj_SqlConnection.State != ConnectionState.Closed)
  {
    mobj_SqlConnection.Close();
  }
  mobj_SqlConnection.Dispose();
}

我一般使用标题SqlHelper来描述我使用的包装器类。代码正在调用。关闭析构函数中的SqlConnection,当对象超出using语句的范围时,我已验证该析构函数正在正确调用。啊,好的。我以为是微软企业图书馆的,这是我们使用的。很明显,有些东西并没有在它应该在的地方关闭。尝试将命令对象上的清理代码移到连接上的清理代码之前。如果您正在使用DataAdapters,那么也可以使用DataAdapters。@LarsTech这似乎有帮助,在进行更改和重新部署之后,我无法再重现错误,尽管我希望能够更好地了解发生了什么。