2010-04-21 21 views
5

Encapsulo mis llamadas de linq a sql en una clase de repositorio que se crea una instancia en el constructor de mi controlador sobrecargado. El constructor de mi clase de repositorio crea el contexto de datos para que, durante la vida de la carga de la página, solo se use un contexto de datos.¿Por qué mis conexiones no están cerradas incluso si elimino explícitamente el DataContext?

En mi destructor de la clase de repositorio, llamo explícitamente a la eliminación del DataContext, aunque no creo que sea necesario.

Utilizando el monitor de rendimiento, si veo mis Conexiones de usuario contar y cargar una página varias veces, el número aumenta una vez por carga de página. Las conexiones no se cierran ni se vuelven a utilizar (durante unos 20 minutos).

Intenté poner Pooling = false en mi configuración para ver si esto tenía algún efecto pero no fue así. En cualquier caso, con la agrupación no esperaría una nueva conexión para cada carga, esperaría que reutilice las conexiones.

He intentado poner un punto de ruptura en el destructor para asegurarme de que el material está siendo golpeado y, por supuesto, lo es. ¿Entonces que esta pasando?

algo de código para ilustrar lo que he dicho anteriormente:

El controlador:

public class MyController : Controller 
{ 
    protected MyRepository rep; 

    public MyController() 
    { 
     rep = new MyRepository(); 
    } 
} 

El repositorio:

public class MyRepository 
{ 
    protected MyDataContext dc; 

    public MyRepository() 
    { 
     dc = getDC(); 
    } 

    ~MyRepository() 
    { 
     if (dc != null) 
     { 
      //if (dc.Connection.State != System.Data.ConnectionState.Closed) 
      //{ 
      // dc.Connection.Close(); 
      //} 
      dc.Dispose(); 
     } 
    } 

    // etc 
} 

Nota: añado una serie de consejos e información de contexto a la DC para fines de auditoría. Esta es la razón fundamental por que quiero una conexión por cada carga de la página

Actualización: Después de haber implementado IDisposable en mi repositorio y en mi clase del controlador que no podía encontrar una manera de llamar específicamente al método Dispose en mi controlador ya que el el controlador es creado y destruido detrás de escena por MvcHandler. Sin embargo, encontré que mis conexiones se cerraban de todos modos. No estaba cómodo sabiendo que esta funcionaba pero sin saber por qué así que hice algo de investigación y encontré una cotización de MSDN que me hizo feliz:

Cuando se completa la ejecución, el MvcHandler comprobará si el controlador implementa el IDisposable interfaz, y si es así, invocará Dispose en el controlador para limpiar los recursos no administrados.

Informe final de actualización: Después de un mes más o menos con el que trabaja este Ahora he eliminado todo este código e ido abajo de la MS aconsejó ruta de envolver un "uso" declaración de todo el código en mis métodos de repositorios públicos y pasando esta DC a los métodos privados. Esto parece un poco derrochador y repetitivo, y también da como resultado que se abran y cierren algunas conexiones más. Pero estaba obteniendo linq en sql caché que solo pude resolver reiniciando el DC.

Respuesta

4

El patrón correcto (versión corta pero suficiente) aquí es:

public class MyRepository : IDisposable 
{ 
    ... // everything except the dtor 

    public void Dispose() 
    { 
     if (dc != null) 
     { 
      dc.Dispose(); 
     } 
    } 
} 

public class MyController : Controller, IDisposable 
{ 
    protected MyRepository rep; 

    public MyController() 
    { 
     rep = new MyRepository(); 
    } 

    public void Dispose() 
    { 
     if (rep!= null) 
     { 
      rep.Dispose(); 
     } 
    } 
} 

Y ahora se puede (debe) utilizar myController con la cláusula usando:

using (var ctl = new MyController()) 
{ 
    // use ctl 
} 

Editar:
di cuenta de que las cascadas de myController, código agregado. Esto muestra cómo se extiende la propiedad indirecta de un recurso no administrado.

Edición 2:
Esto también es correcto (como sería un try/finally):

var ctl = GetController(); 
using (ctl) 
{ 
    // use ctl 
} 

Si no puede mantenerlo local para 1 método, simplemente hacer lo mejor para llamar a CTL .Dispose() en un evento de Cierre o similar.

+0

ahh, gracias. Me preguntaba si mi código necesitaba esa adición también (refiriéndose a la edición) –

+0

No estoy tan seguro del último bit. MVC genera mi controlador, entonces, ¿cómo hago para asegurarme de que esté dispuesto correctamente? –

+0

@Chris, solo tenga cuidado al heredar, observo que ha protegido los campos. No lo hubiera hecho –

2

Destructores solo son llamados por el GC. Su MyRepository debe implementar el patrón Dispose y desechar el DC allí.

Consulte esta pregunta para obtener más detalles. In C# what is the difference between a destructor and a Finalize method in a class?

MyRepository debe implementar IDisposable, los objetos desechables deben desecharse allí si los mantiene abiertos durante toda la vida útil del objeto.

mayoría de las veces cuando se utiliza un objeto desechable que debe envolver en un bloque mediante

es decir

using(var dc = getDC()) 
{ 
    //do stuff with the dc 
}//the dc will be Disposed here 

Editar: Enlace a la guía de Lengua para C# destructores http://msdn.microsoft.com/en-us/library/66x5fx1b(v=VS.100).aspx

+0

Y __not__ implementar un destructor. No sirve para nada en esta clase. –

+0

ahh, ¿estás diciendo que un Dispose no se debe invocar en un destructor? –

+0

Los destructores acordados deberían ser raramente utilizados en una aplicación C#. –

0

Estoy de acuerdo con el hecho de que las piezas desechables eran incorrectas y las sugerencias anteriores por Henk Holterman y Darryl Braaten son muy buenas y no creo que respondan a su pregunta subyacente.

La respuesta a su pregunta es que la invocación de Dispose en MyRepository (suponiendo que es un DataContext) no cierra la conexión. Simplemente devuelve la conexión al grupo para el próximo uso.

This SO Post, explica cuándo debe preocuparse de conexiones de cierre ...

+0

La pregunta original ya aborda el agrupamiento ("Las conexiones no se cierran ni se vuelven a usar ...") –

+0

¿Puede volver a redactar eso? No sigo? – Nix

+0

No parece que la conexión se devuelva al grupo. Si la agrupación está activada o desactivada, las conexiones nuevas siempre se realizan y no se reutilizan. –

Cuestiones relacionadas