1

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

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

...并且在我的应用程序中引发了匹配的异常。

这些是池连接,并且曾经有一段时间连接池与应用程序角色不兼容 - 事实上,Microsoft 的旧建议是禁用连接池(!!) 但随着sp_unsetapprole的引入,现在(理论上)可以在将连接返回到池之前清理连接。

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

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

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

欢迎提出想法或建议。

4

4 回答 4

1

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

于 2009-02-16T13:43:42.747 回答
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. 这是您创建连接的地方。

客户端代码如下所示:

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.
}
于 2009-02-17T16:00:19.147 回答
1

不,这是不可能的。

于 2009-08-25T15:47:38.927 回答
1

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

于 2015-09-14T13:51:10.813 回答