2009-06-03 4 views
0

J'ai une méthode générique pour appeler une procédure stockée dans ASP.NET:Connexion à SQL ne se ferme pas après appel à DB dans ASP.NET

public SqlDataReader ExecuteStoredProc(string sprocName, SqlParameter[] SqlP) 
     { 
      SqlDataReader iReader; 
      SqlCommand sql = new SqlCommand(); 

      sql.CommandText = sprocName; 
      sql.CommandType = CommandType.StoredProcedure; 
      sql.Connection = ConnStr; 
      if (SqlP != null) 
      { 
       foreach (SqlParameter p in SqlP) 
       { 
        sql.Parameters.Add(p); 
       } 

      } 
      sql.Connection.Open(); 
      iReader = sql.ExecuteReader(CommandBehavior.CloseConnection); 
      sql.Dispose(); 

      return iReader; 
     } 

Même si je fais appel CommandBehavior.CloseConnection la connexion est ne pas fermer. Je peux obtenir les données correctement la première fois que je demande une page. Sur le rechargement, j'obtiens l'erreur suivante:

The connection was not closed. The connection's current state is open. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The connection was not closed. The connection's current state is open.

Source Error:

Line 35: Line 36: } Line 37: sql.Connection.Open(); Line 38: iReader = sql.ExecuteReader(CommandBehavior.CloseConnection); Line 39: sql.Dispose();

Enfin, si je mets sql.Connection.Close(); avant sql.Dispose(); Je reçois une erreur indiquant qu'iReader n'est pas lisible car il a déjà été fermé.

De toute évidence, je ferme mal ma connexion, quelqu'un peut-il me diriger dans la bonne direction?

Répondre

4

Lorsque vous retournez un DataReader, la connexion sous-jacente doit rester ouverte. C'est la responsabilité du consommateur de nettoyer correctement les ressources.

public SqlDataReader ExecuteStoredProc(string sprocName, SqlParameter[] SqlP) 
{ 
    SqlCommand sql = new SqlCommand(); 

    sql.CommandText = sprocName; 
    sql.CommandType = CommandType.StoredProcedure; 
    sql.Connection = ConnStr; 
    if (SqlP != null) 
    { 
     foreach (SqlParameter p in SqlP) 
     { 
      sql.Parameters.Add(p); 
     } 

    } 
    sql.Connection.Open(); 
    return sql.ExecuteReader(CommandBehavior.CloseConnection);   
} 

public void ConsumingMethod() 
{ 
    using(SqlDataReader reader = ExecuteStoredProc("MyProc", params)) 
    { 
     while(reader.Read()) 
     { 
      //work with your reader 
     } 
    } 
} 
+0

Je suis d'accord avec votre approche "la responsabilité du consommateur de nettoyer correctement les ressources.", Mais ce n'est généralement pas à compter sur cela, le consommateur est trop paresseux pour le faire. –

+0

Merci cela a aidé. J'ai ajouté un iReader.Close() à mon consumermethod après ma boucle while. – RedWolves

+0

Vous n'avez pas besoin de fermer et de disposer de la connexion que vous créez dans ExecuteStoredProc? –

1

Je suggérerais d'encapsuler la connexion sql avec une instruction "using", et cela s'occupera de la plupart des problèmes de connexion sql.

using (var conn = new SqlConnection("...")) 
{ 
    conn.Open(); 
    using (var cmd = conn.CreateCommand()) 
    { 
     cmd.CommandText = "..."; 
     using (var reader = cmd.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       // ... 
      } 
     } 
    } 

}

+0

Aussi, je ne suggérerai pas de retourner SqlDataReader, il est préférable d'initialiser votre objet personnalisé, puis retourner votre objet. –

0

L'idée est de faire un Connection.Close(); Une fois que vous avez terminé avec le SqlReader, donc, au lieu de placer l'instruction close() avant la commande SqlReader.Dispose(), vous devez le placer ci-dessous.

0

Ceci est ma façon préférée de traiter IDataReader. Laissez l'appelant créer une instance SqlConnection et passe aux méthodes.

Il est coûteux de créer une instance SqlConnection. Et vous finirez par appeler la même méthode ExecuteStoredProc plusieurs fois dans une situation différente.

Ainsi, je refactorise la méthode ExecuteStoredProc en ajoutant l'instance SqlConnection dans le cadre du paramètre.

using (SqlConnection conn = new SqlConnection()) 
{ 
    conn.ConnectionString = // Connection String; 
    conn.Open(); 

    using (IDataReader reader = foo.ExecuteStoredProc(conn, sprocName, SqlP)) 
    { 
     // Process IDataReader 
    } 
} 
Questions connexes