I wanted to ask what is the common way of using database connections and closing them.
This is my program, but I see in an exeption, the connection.Close() will not execute.
Should i use a try-catch for the whole block? because for some reason i see most people doesnt.
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
using (SqlCommand command = new SqlCommand())
{
command.CommandText = "procedure";
command.Connection = connection;
command.CommandType = CommandType.StoredProcedure;
tmpParameter = DBUtils.createInSQLParam("#ImageID", SqlDbType.SmallInt, htmlImageId);
command.Parameters.Add(tmpParameter);
command.Connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
htmlImageDetails = GetHtmlImageDetailsFromReader(reader, true, out newId);
reader.Close();
}
connection.Close();
return htmlImageDetails;
}
}
You don't have to do it explicitly, because your SqlConnection instance will always be disposed (and then, connection closed) thanks to the using syntactic sugar.
You are opening the connection with a using block, and this means that the compiler will make sure that Dispose() gets called on the connection, which will call Close(). So not to worry, you don't need to Close() the connection yourself, even in case of an Exception.
Should i use a try-catch for the whole block? because for some reason
i see most people doesnt.
No. Since you are using using statement, that translates into try-finally block, so even if an exception occurs it will ensure the disposal of object.
using Statement (C# Reference)
The using statement ensures that Dispose is called even if an
exception occurs while you are calling methods on the object. You
can achieve the same result by putting the object inside a try block
and then calling Dispose in a finally block; in fact, this is how the
using statement is translated by the compiler.
SqlConnection.Dispose ensures that the connection is closed.
To ensure that connections are always closed, open the connection
inside of a using block, ....... Doing so ensures that the connection
is automatically closed when the code exits the block.
Related
I was given a quite old project to look after. During some debugging, I realise the developer did this:
using (var datareader = await readerhelper.GetReader(para1, para2))
{
var result = _mapper.Map<IDataReader, IEnumerable<object>>(datareader);
}
In the readerHelper, we have code like this:
public static async Task<SqlDataReader> GetReader(some parameters)
{
using (SqlCommand sqlCommand= new SqlCommand())
{
SqlConnection conn = new SqlConnection("connString");
sqlCommand.Connection = conn;
// open the query
var sqlDataReader = await sqlCommand.ExecuteReaderAsync(CommandBehavior.CloseConnection);
return sqlDataReader;
}
}
As we can see, these code do not dispose the SqlConnection, but the connection indeed got closed when sqlDataReader finishes (as the CommandBehavior.CloseConnectionis used).
From application insights, I saw some unhandled exception such as this:
System.InvalidOperationException
at System.Data.SqlClient.SqlConnection.GetOpenTdsConnection
Outer Message
A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.
Innermost Message
Invalid operation. The connection is closed.
I can't link these exceptions to anything and I can't see any background timer or task. So could this error be linked to the fact that we don't dispose connection (we do close it for sure).
The developer said he did this way as it takes some resource and time to create SQL connection, as the connection is closed by the reader anyway, he doesn't think there is any problem.
Is he correct? Or the exceptions I saw indeed linked to the fact that we do not dispose SqlException?
sc is a SQL connection passed in from the calling function
I'm using one SQL connection throughout my entire program and having each subfunction open and close it as needed. (I read this was fine, because the SQLConnection class has it's own connection pooling functionality)
string q = "this would be a query";
using (SqlCommand cmd = new SqlCommand(q, sc))
{
cmd.Parameters.Add("#ID", SqlDbType.Int);
cmd.Parameters["#ID"].Value = (an id that is passed in);
try
{
sc.Open();
using (var reader = cmd.ExecuteReader())
{
if(reader.read())
{ logic that might throw exception }
else
{ logic that might throw exception }
}
sc.Close();
}
catch (Exception e)
{
alert user, program does not halt but current function returns
}
}
So the connection opens and the command attempts to execute and some logic is performed that might throw an exception. (I'm not expecting it to) This function is part of a larger program that is processing a large dataset. If it fails DUE TO AN EXCEPTION it needs to note it, but it also needs to attempt to keep running.
Other parts of the program are sharing this connection and opening and closing it as they need it and I've used this basic template for all queries in the program.
It just occurred to me that if an exception occurred, the connection might not be closed. Am I correct in thinking that? My original concern when writing this is that the sc.Open() would be the thing that would throw an exception, but as I've used this in multiple places I've realized that this was short sighted because the connection could open and then any number of steps between the close could throw an exception.
Do I need additional logic here to make sure this connection is closed and the program can attempt to continue running?
If my understanding is correct that the connection needs to be closed in the event of an exception between the open and close I think I have 2 options :
try/catch between the open and close
sc.Close() in the catch block (Bonus concern : If the sc.Open() throws an exception and catch block tries to sc.Close() will an additional exception be thrown?)
You do not need to worry about closing the connection. The connection is closed automatically when it disposed by the using statement within which the connection is created.
In the event of an exception, the connection will still be disposed (and thus closed) because that's how a using statement is designed to work.
You have the State property of the SqlConnection that you can use to determine what state the last network operation left the connection in. This property is described here: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.state(v=vs.110).aspx
I would recommend reacting to exceptions in the SqlConnection (such as Open) and in the SqlCommand separately, because, in my experience, you will usually want to take different actions. Even with the overall approach you want to take,
if you can't open your connection, there is no point in preparing the query,
and you likely want to say something different about inability to open the connection than you would if the query failed. I would move the sc.Open() before the creation of the SqlCommand and try/catch around that.
Clarification on the above answer by #roryap - there is no need for sc.Close() if your connection is created in a using statement but from your question I guess it's not. In which case you should probably add a finally section to the try catch block and close the connection in there.
Its better that you close the connection in finally block
finally
{
sc.Close();
}
After try block is completed, the finally block will work.
In a case of an exception, finally block also works.
So the connection will closed in any case.
I tried to search for this on SO but couldn't find it. Maybe I didn't search properly and it is a duplicate of something.
But I would like to ask a question: what is the difference between opening a DB connection inside a using(...) block and outside.
For clarify what I mean, look at the code snippets below.
Snippet where we open a DB connection outside "using" block:
if (_dbConn.State != ConnectionState.Open)
_dbConn.Open();
using (var oraclePackage = new OraclePackage())
{ // some DB function here... }
Snippet in which a DB connection is opened inside a "using" block:
using (var oraclePackage = new OraclePackage())
{
if (_dbConn.State != ConnectionState.Open)
_dbConn.Open();
// some DB functions here
}
Would the block where I DO NOT open a connection inside "using" still close it in case of an exception or would it be left open?
Would the block where I DO NOT open a connection inside "using" still close it in case of an exception or would it be left open?
In both of those examples, the connection would still be open, until perhaps a finaliser ran, if one ever did. Neither has a using that is "using" dbConn.
The code:
using(someObject)
{
// More code here.
}
Is equivalent to:
try
{
// More code here.
}
finally
{
if(someObject != null)
((IDisposable)someObject).Dispose();
}
And the code:
using(var someObject = new SomeClass())
{
// More code here.
}
Is equivalent to:
var someObject = new SomeClass();
try
{
// More code here.
}
finally
{
if(someObject != null)
((IDisposable)someObject).Dispose();
}
(Null checks might be optimised out in cases where the object clearly cannot be set to null at any point).
Your code does this with oraclePackage so oraclePackage will be guaranteed to have Dispose() called on it, whether the block of code is left due to an exception or not. You code does not do this with dbConn.
As such, if you don't explicitly call dbConn.Dispose() or dbConn.Close() (which dbConn.Dispose() almost certainly calls into) the connection will not be closed.
If there are no remaining GC roots that can access dbConn then it's likely that eventually the internal object that represents the actual open connection will be finalised, which will lead to the connection being closed, but this is not guaranteed to happen or to happen in a timely manner, and it is quite likely not to work as well with the internal caching mechanism most IDbConnection implementations use.
As you are not applying using on connection object the connection will remain open if exception occurs...so you need finally block which close your connect even there is exception.
so your code will be , as you are not applying using on connection object
try
{
using (var oraclePackage = new OraclePackage())
{
if (_dbConn.State != ConnectionState.Open)
_dbConn.Open();
// some DB functions here
}
}
finally
{ _dbConn.Close(); }
Using statement does not handle any exceptions. It is responsible for calling IDisposable on current object (DB connection).
This means that no matter if you open connection inside or outside the using block, at the end of the block the connection will be disposed
I am working on a new project and have a section of code where I don't want to actually handle exceptions but make sure any DB connections are closed. I am wondering which will be the best way to handle the issue. I see 2 ways but am not sure which will be clearer:
SqlConnection con = new SqlConnection(connectionstring);
try
{
con.open()
//DoStuff
}
catch(Exception)
{
throw;
}
finally
{
con.close();
con.dispose();
}
OR
try
{
con.open()
//DoStuff
}
finally
{
con.close();
con.dispose();
}
Either way I pass the exception up to the calling code to be handled but still clean up the connections.
You can use using statement to enclose your connection. It would translate into try-finally block, like in your second code example.
Since you are not doing anything with your exception (like logging) you can leave out the catch block.
You can use using like:
using (SqlConnection con = new SqlConnection(connectionstring))
{
}
This will ensure your connection is disposed at the end of using block, even in case of an exception. You can only use using statement with those objects which implements IDisposable interface.
If you are going to deal with objects which doesn't implement IDisposable then your second code snippet (With try-finally) is good enough, since you want the exception to bubble up.
So, I'm getting the error as per my title line. Seems pretty self- explanatory, but my understanding is that objects within the "using" block are disposed of? This error appeared after another minor bug interrupted code execution, so perhaps I'm stuck with an open reader that I need to close or shut down? Any help would be appreciated?
public override long GetStatsBenchmark(String TableName)
{
using (SqlCommand cmd = new SqlCommand("sprocReturnDataPointBenchmark", this.sqlConnection))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlParameter outputParameter = new SqlParameter
{
ParameterName = "#benchmark",
Direction = System.Data.ParameterDirection.Output,
SqlDbType = System.Data.SqlDbType.BigInt,
};
cmd.Parameters.Add(outputParameter);
SqlParameter inputParameter = new SqlParameter
{
ParameterName = "#tblName",
Direction = System.Data.ParameterDirection.Input,
SqlDbType = System.Data.SqlDbType.NVarChar,
Value = TableName
};
cmd.Parameters.Add(inputParameter);
cmd.ExecuteNonQuery();
return (long)outputParameter.Value;
}
}
I do not think that the code you have shown is the cause of the problem. While it is good practice to dispose of SqlCommand (IDbCommand) objects, in practice I have not found it to be necessary. What is necessary is to dispose of SqlDataReader (IDataReader) objects after you have finished using them. As the error message suggests, look for a usage of an SqlDataReader object in your code that is not being disposed. The exception may be thrown from the code you are displaying, but I would suspect that the cause is because of an SqlDataReader associated with the same SqlConnection used earlier in the program execution that has not been disposed.
An issue with the using clause is that it does not provide a way to process exceptions in the implicit try/finally block that the compiler generates for you.
You can
1) wrap your using clause with a try/catch, or
2) manually code a try/catch/finally instead of using, calling Dispose in the finally block and adding exception handling in a catch block.
There are slight drawbacks to either technique, but either will work
You can add MARS (multiple active result sets) to your connection string, to allow multiple recordset (or similar) open at the same time.
Add
MultipleActiveResultSets=true;
or
MARS Connection=True;
to your connection string (http://www.connectionstrings.com/sql-server-2008) and this will allow multiple handles, but if the previous operation has been "interrupted" in an exception, try avoid using "USING" or use a try/catch inside it.