2010-10-28 11 views
8

Recibo el mensaje de error "No se permite nueva transacción porque hay otros subprocesos en ejecución" en una aplicación en la que estoy trabajando. Ha surgido durante la refactorización y específicamente durante la creación de un conjunto de pruebas.¿Hay alguna manera de detectar lectores abiertos en una SqlConnection?

Me doy cuenta de que, al mirar a mi alrededor, probablemente tenga abierto un lector de datos cuando estoy creando la transacción, sin embargo es una aplicación compleja y no es obvio dónde está el problema. Por lo tanto, me gustaría poder determinar qué lectores están conectados a SqlConnection en cuestión.

Idealmente, quiero poder agregar un reloj en Visual Studio y luego pasar al modo de depuración para ver cuándo cambia el número de lectores conectados.

¿Hay alguna manera de hacer esto? Estoy trabajando en C#.

Gracias de antemano.

Martin

Respuesta

7

¡Uf! ¡Ahora sé mucho más sobre Reflection!

Para cualquiera que esté buscando la respuesta a esto, aquí hay un método que devuelve la cantidad de lectores de datos en una SqlConnection.

public static int CountConnectedReaders(SqlConnection conn) 
{ 
    int readers = 0; 
    Type t = conn.GetType(); 
    MemberInfo[] minf = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance); 
    for (int i = 0; i < minf.Length; i++) 
    { 
    if (minf[i].Name == "get_InnerConnection") 
    {      
     MethodInfo methinf = (MethodInfo)minf[i]; 

     object result = methinf.Invoke(conn, new object[0]); 

     PropertyInfo[] pinfs = result.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance); 
     foreach (PropertyInfo pinf in pinfs) 
     { 
     if (pinf.PropertyType.Name == "DbReferenceCollection") 
     { 
      object dbrc = pinf.GetValue(result, new object[0]); 
      if (dbrc == null) readers = 0; 
      else 
      { 
      MemberInfo[] dbrcInfs = dbrc.GetType().GetMembers(BindingFlags.NonPublic | BindingFlags.Instance); 
      foreach (MemberInfo dbrcInf in dbrcInfs) 
      { 
       if (dbrcInf.Name == "_dataReaderCount") 
       { 
       FieldInfo finf = (FieldInfo)dbrcInf; 
       readers = (Int32) finf.GetValue(dbrc); 
       } 
      } 
      } 
     } 
     } 
    } 
    } 

    return readers; 
} 

Curiosamente, usando esto en mi código de problema sugiere que no hay lectores de datos abiertos en la conexión cuando llegue a la "Nueva transacción no está permitido porque hay otros subprocesos que se ejecutan" error para volver a la mesa de dibujo (o al menos otra pregunta SO) con eso.

+0

Guau, alguien votó esta respuesta (que me tomó horas para hacer ejercicio) como "no útil". Me encantaría saber por qué. – marsbard

+0

Idiotas en todas partes. Buen hallazgo: sabía que no había forma de obtenerlo de la interfaz documentada, pero obviamente la conexión necesitaba tener una referencia en alguna parte. Bueno, al menos un recuento de lectores abiertos. – TomTom

+0

Bien hecho. Votado +1. – TomTom

1

Usted puede encontrar este thread de interés.

Editar: Parece que obtuvieron en DbConnectionInternal con Reflector, y hay una versión gratuita disponible. En cuanto a la reflexión, no es demasiado complicado en realidad. Hay una descripción decente en MSDN.

Edit2: Me acabo de dar cuenta de que ya te has dado cuenta. Estupendo. :) Dejaré la edición en caso de que alguien más quiera más información.

+0

Ese es un hilo interesante y relevante. Sin embargo, estoy un poco fuera de mi alcance cuando trato de usar Reflection :). Tampoco pude encontrar el DBConnectionInternal al hacer clic a través de los helpers de Intellisense en el modo de depuración. – marsbard

+0

Gracias por el enlace a Reflector. Se ve bien. – marsbard

Cuestiones relacionadas