Closing An SqlDataReader that might not have been initialized - c#

I'm stuck in a cycle of different compiler errors and I need some assistance.
So case 1: SqlDataReader executed outside of try block allows closing it later, however, leaves the reader exceptions unhanded.
var cmd = String.Format("SQL COMMAND HERE");
var command = new SqlCommand(cmd, conSQL);
SqlDataReader readerSql = command.ExecuteReader(); //Unhandled Exceptions here
try
{
while (readerSql.Read())
{....}
}
catch (SqlException e)
{...}
finally
{
readerSql.Close(); //Compiler error: Might not have been initialized
}
Case 2: Reader is executed inside try block, reader exceptions can be handled, however, reader cannot be closed on exceptions.
SqlDataReader readerSql;
try{
readerSql = command.ExecuteReader();
while (readerSql.Read())
{...}
readerSql.Close(); //Does not close on exceptions
}
catch (SqlException e)
{
readerSql.Close(); //Compiler error: Might not have been initialized
}
finally
{
if(readerSql != null) //Compiler Error on if statement, same as below
readerSql.Close(); //Compiler error: Might not have been initialized
}

Use the using statement, it solves your issue:
The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object.

As Alioza says the best method is the using statement.
using (var readerSql = command.ExecuteReader()) {
while (readerSql.Read()) {
{....}
}
}
https://msdn.microsoft.com/en-us/library/yh598w02.aspx (using statement documentation)

you can use the using statement and not worry about closing.
using(SqlDataReader readerSql = command.ExecuteReader()){
try{
while (readerSql.Read())
{....}
}
catch (SqlException e)
{
//execption
}
}

Related

There is already an open DataReader associated with this Command, without nested datareaders

I'm getting the following error intermittently.
There is already an open DataReader associated with this Command which must be closed first.
I read that this can happens when there are nested DataReaders in the same connection, but in my case, I'm using the following code to execute all queries.
private SqlTransaction Transaction { get; set; }
private SqlConnection Connection { get; set; }
private DbRow Row {get; set;}
public Row Exec(string sql){
try{
//Begin connection/transaction
Connection = new SqlConnection(connectionString);
Connection.Open();
Transaction = Connection.BeginTransaction("SampleTransaction");
//create command
SqlCommand command = new SqlCommand(sql, Connection);
command.Transaction = Transaction;
//execute reader and close it
//HERE IS THE PROBLEM, THE READER ALWAYS READ UNTIL THE END
//BEFORE ANOTHER CAN BE OPENED
reader = command.ExecuteReader();
while (reader.Read())
{
object[] value = new object[reader.FieldCount];
reader.GetValues(value);
List<object> values = new List<object>(value);
Rows.Add(values);
}
reader.Close();
Transaction.Commit();
Connection.Dispose();
Connection = null;
}
catch
{
Transaction.Rollback();
Connection.Dispose();
Connection = null;
}
finally
{
if (reader != null && !reader.IsClosed) reader.Close();
}
}
This way, The result is stored in an object and there isn't nested readers.
I also read that adding 'MultipleActiveResultSets=True' to connection string can solve the problem when using nested readers.
Does this solution also solve my problem?
As the error is intermitent and only happens in production environment, I can't test it many times.
There is already an open DataReader associated with this Command which must be closed first. at
System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command) at
System.Data.SqlClient.SqlInternalTransaction.Rollback() at
System.Data.SqlClient.SqlTransaction.Rollback() at
Application.Lib.DB.DBSQLServer.Rollback()
at Application.Lib.DB.DBSQLServer.Execute(String sql, Dictionary`2 parameters,
Nullable`1 timeout, Boolean useTransaction) at
Application.UtilDB.Execute(String sql, Dictionary`2 parameters, Nullable`1
timeout, Boolean useTransaction) in c:\Application\DBUtil.cs:line 37 at
Application.A.CollectionFromDataBase(Int32 cenId,
IDB db, Int32 includeId, Boolean allStatus) in c:\Application\Activities.cs:line 64 at
Application.ActivitiesController.CheckForConflictsBeforeSave(String aulId, String insId) in c:\Application\AlocController.cs:line 212
The problem was that, when a query fails, the transaction can't be rolled back because the data reader is already open to process the query.
A second exception is thrown and the first one is lost.
I just placed the rollback inside a try catch block and used the AggregateException class to throw both exceptions.
try
{
Transaction.Rollback();
Connection.Dispose();
Connection = null;
}
catch (Exception ex2)
{
throw new AggregateException(new List<Exception>() { e, ex2 });
}
Although the transaction will be rolled back anyway, I think you can also try to close the data reader before the rollback, so it will probably work.
if (reader != null && !reader.IsClosed)
reader.Close();
Transaction.Rollback();
Since this happens only on production it's more likely that bug is outside the code you attached.
Most common way to prevent this is to always code in following fashion:
reader = command.ExecuteReader();
try
{
for (int i = 0; i < reader.FieldCount; i++)
{
dbResult.Columns.Add(reader.GetName(i));
dbResult.Types.Add(reader.GetDataTypeName(i));
}
while (reader.Read())
{
object[] value = new object[reader.FieldCount];
reader.GetValues(value);
List<object> values = new List<object>(value);
Rows.Add(values);
}
}
finally
{
reader.Close();
}
Notice the finally block, it makes sure reader is closed no matter what. I am under impression that something happens in your code that leaves the reader open but the bug isn't visible in the code you've posted.
I recommend you enclose it in the above try/finally block and your bug is quite likely to be resolved.
Edit, to clarify: This may not resolve whatever bug exists outside the scope of the originally shown code but it will prevent data readers being left open. The finally block I suggested won't block any exceptions, they will be propagated to whatever handler you employ outside of it.

SqlDataReader hangs on Dispose()

I use the following approach to execute queries over database and read data:
using(SqlConnection connection = new SqlConnection("Connection string"))
{
connection.Open();
using(SqlCommand command = new SqlCommand("SELECT * FROM TableName", connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
// read and process data somehow (possible source of exceptions)
} // <- reader hangs here if exception occurs
}
}
While reading and processing data some exceptions can occur. The problem is when exception is thrown DataReader hangs on Close() call. Do you have any ideas why??? And how to solve this issue in a proper way? The problem has gone when I wrote try..catch..finally block instead of using and called command.Cancel() before disposing the reader in finally.
Working version:
using(SqlConnection connection = new SqlConnection("Connection string"))
{
connection.Open();
using(SqlCommand command = new SqlCommand("SELECT * FROM TableName", connection))
{
SqlDataReader reader = command.ExecuteReader();
try
{
// read and process data somehow (possible source of exceptions)
}
catch(Exception ex)
{
// handle exception somehow
}
finally
{
command.Cancel(); // !!!
reader.Dispose();
}
}
}
When an exception occurs you stop processing data before all data is received. You can reproduce this issue even without exceptions if you abort processing after a few rows.
When the command or reader is disposed, the query is still running on the server. ADO.NET just reads all remaining rows and result sets like mad and throws them away. It does that because the server is sending them and the protocol requires receiving them.
Calling SqlCommand.Cancel sends an "attention" to SQL Server causing the query to truly abort. It is the same thing as pressing the cancel button in SSMS.
To summarize, this issue occurs whenever you stop processing rows although many more rows are inbound. Your workaround (calling SqlCommand.Cancel) is the correct solution.
About the Dispose method of the SqlDataReader, MSDN (link) has this to say:
Releases the resources used by the DbDataReader and calls Close.
Emphasis added by me. And if you then go look at the Close method (link), it states this:
The Close method fills in the values for output parameters, return
values and RecordsAffected, increasing the time that it takes to close
a SqlDataReader that was used to process a large or complex query.
When the return values and the number of records affected by a query
are not significant, the time that it takes to close the SqlDataReader
can be reduced by calling the Cancel method of the associated
SqlCommand object before calling the Close method.
So if you need to stop iterating through the reader, it's best to cancel the command first just like your working version is doing.
I would not format it that way.
Open(); is not in a try block and it can throw an exception
ExecuteReader(); is not in a try block and it can throw an exception
I like reader.Close - cause that is what I see in MSDN samples
And I catch SQLexception as they have numbers (like for timeout)
SqlConnection connection = new SqlConnection();
SqlDataReader reader = null;
try
{
connection.Open(); // you are missing this as a possible source of exceptions
SqlCommand command = new SqlCommand("SELECT * FROM TableName", connection);
reader = command.ExecuteReader(); // you are missing this as a possible source of exceptions
// read and process data somehow (possible source of exceptions)
}
catch (SqlException ex)
{
}
catch (Exception ex)
{
// handle exception somehow
}
finally
{
if (reader != null) reader.Close();
connection.Close();
}

TRY-CATCH relative to USING [duplicate]

This question already has answers here:
try/catch + using, right syntax
(9 answers)
Closed 9 years ago.
I've been implementing TRY-CATCH relative to USING like the following example:
private void someDatabaseMethod(string userName) {
try {
using(var conn = new SqlConnection(connString))
using(var comm = new SqlCommand()) {
comm.Connection = conn;
comm.CommandType = CommandType.Text;
comm.CommandText = string.Concat(#"SELECT UserID FROM xxx WHERE UserName = '", userName,#"'");
conn.Open();
object x = comm.ExecuteScalar();
UserID = (x==null)? 0: (int)x;
}
} catch(Exception) {
throw;
}
}
I've just seen this MSDN EXAMPLE which seems to point towards the TRY-CATCH being within the USING. So my example would look like the following:
private void someDatabaseMethod(string userName) {
using(var conn = new SqlConnection(connString))
using(var comm = new SqlCommand()) {
comm.Connection = conn;
comm.CommandType = CommandType.Text;
comm.CommandText = string.Concat(#"SELECT UserID FROM xxx WHERE UserName = '", userName,#"'");
try {
conn.Open();
object x = comm.ExecuteScalar();
UserID = (x==null)? 0: (int)x;
} catch(Exception) {
throw;
}
}
}
Is this a more efficient layout? If so, why?
EXTRA ADDITIONAL NOTE
The reason for the TRY-CATCH is to re-throw the exception so that I bubble it up to the next level - so I'd like to have a CATCH somewhere in the code.
It depends on your goals. If you want to do something with command or connection in catch block, then it should be within using.
TRY-CATCH I use in using only if I want to LOG Exception or it I have transaction - to rollback it in except block.
using is translated by compiler in TRY-FINALLY - you can check it with IL Disassembler (ildasm.exe) or reflector to release your disposable resources.
so that
using is equivalent to :
try
{
//do job
}
finally
{
Resource.Dispose()
}
If you just throw the catched exception, the try-catch block isn't necessary at all. The using will dispose the conenction and command properly.
Second one is more efficient. For first one; you can not access connection object from catch block, and can not close it. Also if you was using a transaction over this connection, you could not rollback the transaction when any error occurs...
Don't catch exceptions you cannot handle at this place.
catch{throw;} is of no use except adding complexity
catch and handle exceptions as near at the exception source as you are able to handle them
Read extensive discussion here

ADO.NET Funny Connection Pool Behaviour when bury SQL Exception

I am catching a sql exception and not rethrowing it. This seems to mean that the connection is not returned to the pool as I would expect. Is this possible?
using (IDbCommand paymentCommand = this.Connection.CreateCommand())
{
try
{
//database stuff
}
catch (SqlException ex)
{
//LOG CALL
}
}
why don't you put using(...){} inside try{} block? This way even if exception is thrown, using block will dispose off IDBcmd obj.
It's not clear in your question how you are creating the connection, but you do need to make sure you Open it, then Close it, regardless of errors or not.
Typically I'll do something like this:
SqlConnection connection = null;
try {
connection.Open();
// Do stuff like run a query, setup your IDbCommand, etc.
} catch (Exception ex) {
// Log error
} finally {
if (connection != null) {
connection.Close();
}
}
This way, no matter what happens, your connection will be closed and returned to the pool. If you fail to Close(), you'll "leak" that connection and eventually run out of pooled connections to draw from. The lifetime of the connection should generally only be as long as it takes to issue your sql command, at which point you should be closing it.
It's not clear what you are experiencing with the connection pool. However, I would definitely wrap your connection in a using statement.
This is what I usually use (note that dac.GetConnection() is simply a class that centralizes the code to get a connection object):
using (SqlConnection connection = dac.GetConnection())
{
using (SqlCommand command = new SqlCommand("myProc", connection))
{
command.CommandType = CommandType.StoredProcedure;
try
{
connection.Open();
//add params, run query
}
catch (Exception ex)
{
//handle/log errror
}
finally
{
if (connection.State == ConnectionState.Open)
connection.Close();
}
}
}

If I catch exceptions inside a using statement for a SqlConnection, does the using still handle closing and disposing my connection?

I'm going through some old C#.NET code in an ASP.NET application making sure that all SqlConnections are wrapped in using blocks.
This piece of code used to open cn and da and close and dispose them in both the catch block and the end of the method. I added the usings and can't figure out for certain if the using blocks still handle disposing of the connection if an exception is thrown in the try and caught in the catch. This question seems to suggest that it does.
using (SqlConnection cn = new SqlConnection(Global.sDSN))
{
using (SqlDataAdapter da = new SqlDataAdapter())
{
// do some stuff
try
{
// do stuff that might throw exceptions
}
catch (catch (System.Exception e)
{
//return something here
// can I ditch these because the using's handle it?
da.Dispose();
cn.Close();
cn.Dispose();
return msg;
}
}
}
Yes, they will. They're basically turned into a finally block.
So something like this:
using (SqlConnection cn = new SqlConnection(Global.sDSN))
{
....
}
is really turned into:
SqlConnection cn = new SqlConnection(Global.sDSN)
try
{
....
}
finally
{
cn.Dispose();
}
more or less - and the finally block is always executed, no matter what might have happened before in the try {.....} block.
When you use a using clause this is what's happening:
myobject = new object();
try{
// do something with myobject
}finally{
myobject.Dispose();
}
Hope this helps,
Best regards,
Tom.

Categories

Resources