检测不可用的池化SqlConnections

时间:2009-02-16 13:39:43

标签: c# sql-server ado.net connection-pooling application-role

当我尝试使用sp_setapprole在SqlConnection上设置应用程序角色时,我有时会在Windows事件日志中收到以下错误...

  

连接已被删除,因为打开它的主体随后假定了一个新的安全上下文,然后尝试在其模拟的安全上下文下重置连接。不支持此方案。请参阅联机丛书中的“模拟概述”。)

...我的应用程序中抛出了匹配的异常。

这些是池连接,有时连接池与app角色不兼容 - 事实上,Microsoft的旧建议是disable connection pooling(!!),但引入了sp_unsetapprole现在(理论上)可以在将连接返回池之前清理连接。

我相信这些错误发生在(由于未知原因)sp_unsetapprole在连接关闭并返回到连接池之前未在连接上运行时。然后,当从池返回此连接时,sp_approle注定会失败。

我可以捕获并处理此异常,但我更愿意检测即将发生的故障并完全避免异常(以及事件日志中的消息)。

是否可以在不引起异常的情况下检测问题?

欢迎提出想法或建议。

4 个答案:

答案 0 :(得分:1)

这是逻辑上的,并没有太多使用sp_setapprole的经验但是在调用之前是否无法检查安全上下文?或者首先检查安全权限和上下文?

答案 1 :(得分:1)

看起来你正在调用sp_setapprole但是没有调用sp_unsetapprole然后让连接只返回池。

我建议使用一个结构(或类,如果你必须在方法中使用它)和IDisposable的实现,它将为你处理这个:

public struct ConnectionManager : IDisposable
{
    // The backing for the connection.
    private SqlConnection connection;

    // The connection.
    public SqlConnection Connection { get { return connection; } }

    public void Dispose()
    {
        // If there is no connection, get out.
        if (connection == null)
        {
            // Get out.
            return;
        }

        // Make sure connection is cleaned up.
        using (SqlConnection c = connection)
        {
            // See (1).  Create the command for sp_unsetapprole
            // and then execute.
            using (SqlCommand command = ...)
            {
                // Execute the command.
                command.ExecuteNonQuery();
            }
        }
    }

    public ConnectionManager Release()
    {
        // Create a copy to return.
        ConnectionManager retVal = this;

        // Set the connection to null.
        retVal.connection = null;

        // Return the copy.
        return retVal;        
    }

    public static ConnectionManager Create()
    {
        // Create the return value, use a using statement.
        using (ConnectionManager cm = new ConnectionManager())
        {
            // Create the connection and assign here.
            // See (2).
            cm.connection = ...

            // Create the command to call sp_setapprole here.
            using (SqlCommand command = ...)
            {
                // Execute the command.
                command.ExecuteNonQuery();

                // Return the connection, but call release
                // so the connection is still live on return.
                return cm.Release();
            }
        }
    }
}
  1. 您将创建与调用sp_setapprole存储过程相对应的SqlCommand。您可以生成cookie并将其存储在私有成员变量中。
  2. 这是您创建连接的位置。
  3. 客户端代码如下所示:

    using (ConnectionManager cm = ConnectionManager.Create())
    {
        // Get the SqlConnection for use.
        // No need for a using statement, when Dispose is
        // called on the connection manager, the connection will be
        // closed.
        SqlConnection connection = cm.Connection;
    
        // Use connection appropriately.
    }
    

答案 2 :(得分:1)

不,这是不可能的。

答案 3 :(得分:1)

这有点脏,但如果您的原始用户拥有VIEW SERVER STATE的权限,select * from sys.sysprocesses将在角色未处于活动状态时返回所有进程,并在当前进程为单行时返回。< / p>