检测不可用的池化SqlConnections

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

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

…并在我的应用程序中抛出匹配的exception。

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

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

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

是否有可能在不引起exception的情况下检测问题?

欢迎提出想法或建议。

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

看起来你正在调用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. } 

不,这是不可能的。

这有点脏,但如果您的原始用户具有VIEW SERVER STATE权限,则select * from sys.sysprocesses将在角色未激活时返回所有进程,并在当前进程时返回单行。