5

Heredé un marco web mediante el cual el desarrollador anterior ha abierto y cerrado sus conexiones a la base de datos en los métodos de inicio/descarga del ciclo de vida de la página. Esencialmente constructor es así (simplificado para demostrar el punto);Cerrar una conexión en el método de "descarga"

public class BasePage 
{ 
    protected DBConnection _conn; 

    public BasePage() 
    { 
     Init += StartConnection; 
     Unload += EndConnection; 
    } 

    private void StartConnection(object sender, EventArgs e) 
    { 
     _conn = new DBConnection(Application["connectionstring"].ToString()); 
    } 

    private void EndConnection(object sender, EventArgs e) 
    { 
     if (_conn == null) 
     return; 

     if (_conn.Connection.State == ConnectionState.Open) 
     { 
    _conn.Close(); 
     _conn.Dispose(); 
     } 
    } 
} 

El desarrollo ha sido bastante rápido desde que llegué aquí, así que nunca dejé de considerarlo. Recientemente, las visitas han aumentado y hemos comenzado a recibir el temido error "Tiempo de espera caducado. El tiempo de espera transcurrido antes de obtener una conexión del grupo ...".

Actualmente estoy revisando el resto del código buscando posibles fugas de conexión, pero el código anterior nunca me ha sentado bien y quiero eliminarlo como un posible culpable. En la pregunta, entonces;

¿Puedo confiar en el método de "descarga" SIEMPRE se está llamando, incluso en el caso de una excepción? ¿O puede alguien ver otros posibles problemas utilizando el patrón anterior que lo haría un sospechoso principal para estas fugas de conexión?

Saludos,

Mikey

EDIT: En la depuración, el método de descarga siempre se llama, incluso si no es una excepción. Realmente solo necesito saber de cualquier escenario en el que no se llame a este método para poder averiguar si este es el bit que necesito para refactorizar primero.

EDITAR: Gracias a quienes han respondido hasta ahora, pero no hagan más recomendaciones sobre la clase IDisposable, o los patrones "usar" o "atrapar/finalmente": ¡esta no era mi pregunta! Mi pregunta es específicamente si una página podría ejecutar su evento "Init" pero luego no ejecutar es un evento "Descargar", y por qué esto podría suceder.

Respuesta

2

No tengo conocimiento definitivo acerca de si esto es seguro, pero examiné el código fuente para la clase System.Web.UI.Page y el evento de descarga es desencadenado por el ProcessRequestCleanup() a menos que la solicitud sea asincrónica o una solicitud de página cruzada. La llamada al método de limpieza está dentro de un bloque finalmente acoplado a un bloque de prueba que rodea el ProcessRequest. La solicitud de proceso está activando todos los eventos del ciclo de vida de la página desde PreInit hasta Procesamiento. Eso significa que la Descarga siempre se activará (excepto en los casos de sincronización y cruce de páginas), incluso si se produce una excepción.

Sin embargo, me sentiría muy incómodo al tener este código en mis páginas ya que el comportamiento de descarga no está exactamente documentado.

0

No. Tome el siguiente ejemplo.

¿Qué sucede si el usuario cierra el navegador? La función Descargar no se llamará y tendrá una conexión abierta a la base de datos.

Esta pregunta Unload en StackOverflow tiene un problema similar que usted está teniendo.

+0

El método de descarga es del lado del servidor, por lo que seguramente no importaría lo que hizo el usuario una vez que se recibió la solicitud. –

+0

"Para la página en sí, use este evento para realizar el trabajo final de limpieza, como cerrar archivos abiertos y conexiones de bases de datos, o terminar el registro u otras tareas específicas de la solicitud". Desde http://msdn.microsoft.com/en-us/library/ms178472.aspx. Así que es posible que estés en algo, pero de nuevo si miras el enlace Descargar en mi publicación verás que no siempre se llama. No cuento con que se me llame, si es posible, prefiero hacer lo que Pranay Rana sugirió, y esa sería la forma correcta de deshacerse de su conexión. – Jethro

+0

Aquí también hay un interesante SO http://stackoverflow.com/questions/302149/is-it-acceptable-to-keep-a-db-connection-open-for-the-life-of-the-page link, tal vez el "Tiempo de espera expirado" es causado por otra cosa, intente utilizar el Analizador de SQL para ver qué sucede en segundo plano. – Jethro

2

siempre hago uso de la utilización de bloques soemthing como a continuación

using(SqlConnection) 
{ 

} 

de modo que nunca causa ningún problema

si no quieres que escribir el código para abrir la conexión y otra vez crear una clase

public class SqlConnectionManager 
{ 
    public SqlConnection GetSqlConnectionManager() 
    { 
     //create and return connection 
     //SqlConnection con = new SqlConnection(); 
     //return con; 
    } 

} 

En Usted archivos de clase

SqlConnection conn = null; 
using (conn = (new SqlConnectionManager()).GetSqlConnectionManager()) 
{ 
    //do work with connection 
} 

Por lo tanto, no es necesario que escriba el código una y otra vez y tampoco es necesario escribir el código para cerrar la conexión porque se elimina automáticamente mediante el uso de bloque.

+0

Saludos, Esto es exactamente lo que hago normalmente (y casi con seguridad lo que haré finalmente una vez que reciba mi pregunta). Realmente necesito saber específicamente si debería centrarme en este escenario en particular (el de descarga). –

1

EDITAR: Según la respuesta de PHeiberg esto es definitivamente posible en .net 4 y uno puede suponer que la descarga siempre se llamará.

Revisé el código .net 2.0 también y lo mismo también es cierto allí.

+0

Esto no es realmente cierto (ver otros comentarios) –

+0

Thx para señalarlo. – marto

1

A (muy) prueba rápida (servidor web VS2010, v4 .net) me ha demostrado que el evento Unload es llama cuando se produce una excepción no controlada (al menos si se cría en Load), por lo que al principio parece deberia de funcionar.

El patrón como se muestra en el ejemplo es solo dispose 'conectando la conexión si la conexión estaba abierta.

Como _conn está protegido, las páginas que descienden de BasePage pueden interactuar con _conn y modificar su valor. Hay dos maneras de clases descendientes de romper el patrón:

  1. llamada _conn.Close() directamente. Si la conexión no está abierta, no está dispuesta en EndConnection.

  2. Modifique el valor de _conn poniéndolo en nulo o asignándole una nueva instancia de DBConnection.

considerar cambiar su método de EndConnection, por lo que es _conn siempre dispuesto.

private void EndConnection(object sender, EventArgs e) 
{ 
    if (_conn == null) 
    { 
     return; 
    } 
    if (_conn.Connection.State == ConnectionState.Open) 
    { 
     _conn.Close(); 
    } 
    _conn.Dispose(); // always dispose even if not actually open. It may have been closed explicitly elsewhere. 
} 

La carcasa 2 no puede ser atrapada por EndConnection. Considere hacer _conn privado y proporcionando una propiedad getter:

private DBConnection _conn; 

protected DBConnection Connection { 
    get 
    { 
     return _conn; 
    } 
} 

que impide clases descendientes de cambiar el valor de _conn.

Por último, ¿es DBConnection una clase propia? Solo pregunto mientras cita "_conn.Connection.State" en lugar de simplemente _conn.State. Si es así, simplemente verifique que el método Dispose de DBConnection elimine correctamente su instancia de Connection.

+0

Gracias por estos –

Cuestiones relacionadas