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

c# - net - Detectando SqlConnections agrupadas inutilizables



max pool size web config (4)

Cuando intento establecer un rol de aplicación en un SqlConnection con sp_setapprole , a veces obtengo el siguiente error en el registro de eventos de Windows ...

La conexión se ha eliminado porque el principal que la abrió posteriormente asumió un nuevo contexto de seguridad y luego trató de restablecer la conexión en su contexto de seguridad suplantado. Este escenario no es compatible. Consulte "Descripción general de suplantación de identidad" en Libros en pantalla.)

... y se lanza una excepción coincidente en mi aplicación.

Estas son conexiones agrupadas, y hubo un momento en que la agrupación de conexiones era incompatible con las funciones de la aplicación; de hecho, el viejo consejo de Microsoft era deshabilitar la agrupación de conexiones (!!) pero con la introducción de sp_unsetapprole ahora (en teoría) es posible limpie una conexión antes de devolverla a la piscina.

Creo que estos errores ocurren cuando (por razones desconocidas) sp_unsetapprole no se ejecuta en la conexión antes de que se cierre y se devuelva al grupo de conexiones. sp_approle está condenado a fallar cuando se devuelve esta conexión desde el grupo.

Puedo detectar y manejar esta excepción, pero preferiría detectar la falla inminente y evitar la excepción (y los mensajes en el registro de eventos) por completo.

¿Es posible detectar el problema sin causar la excepción?

Pensamientos o consejos bienvenidos.


Esto es un poco sucio, pero si su usuario original tiene derechos para VIEW SERVER STATE , select * from sys.sysprocesses devolverá todos los procesos cuando el rol no esté activo y una sola fila para el proceso actual cuando sea.


Esto es lógico y no tiene mucha experiencia con el uso de sp_setapprole, pero ¿no sería posible verificar el contexto de seguridad antes de realizar la llamada? O, alternativamente, verifique el permiso de seguridad y el contexto primero.


Parece que estás llamando a sp_setapprole pero no llamando a sp_unsetapprole y luego dejando que la conexión solo se devuelva al grupo.

Sugeriría usar una estructura (o una clase, si tiene que usar esto en todos los métodos) con una implementación de IDisposable que se encargará de esto:

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. Creará el SqlCommand que corresponde a llamar al procedimiento almacenado sp_setapprole. También puede generar la cookie y almacenarla en una variable miembro privada.
  2. Aquí es donde creas tu conexión.

El código del cliente se ve así:

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. }


No, no es posible.