I am just looking at the using statement, I have always known what it does but until now not tried using it, I have come up with the below code:
using (SqlCommand cmd =
new SqlCommand(reportDataSource,
new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString)))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
This seems to work but is there any point in this since as far as I can tell I would still need to enclose this in a try catch block to catch unforseen errors e.g. sql server down. Am I missing something?
As far as I can currently see it just stops me closing and disposing of cmd but there will be more lines of code due to the try catch still being needed.
When doing IO work I code to expect an exception.
SqlConnection conn = null;
SqlCommand cmd = null;
try
{
conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString)
cmd = new SqlCommand(reportDataSource, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
conn.Open(); //opens connection
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
catch(Exception ex)
{
Logger.Log(ex);
throw;
}
finally
{
if(conn != null)
conn.Dispose();
if(cmd != null)
cmd.Dispose();
}
Edit: To be explicit, I avoid the using block here because I believe it to be important to log in situations like this. Experience has taught me that you never know what kind of weird exception might pop up. Logging in this situation might help you detect a deadlock, or find where a schema change is impacting a little used and little tested part of you code base, or any number of other problems.
Edit 2: One can argue that a using block could wrap a try/catch in this situation, and this is completely valid and functionally equivalent. This really boils down to preference. Do you want to avoid the extra nesting at the cost of handling your own disposal? Or do you incur the extra nesting to have auto-disposal. I feel that the former is cleaner so I do it that way. However, I don't rewrite the latter if I find it in the code base in which I am working.
Edit 3: I really, really wish MS had created a more explicit version of using() that made it more intuitive what was really happening and given more flexibility in this case. Consider the following, imaginary code:
SqlConnection conn = null;
SqlCommand cmd = null;
using(conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString),
cmd = new SqlCommand(reportDataSource, conn)
{
conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString);
cmd = new SqlCommand(reportDataSource, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
catch(Exception ex)
{
Logger.Log(ex);
throw;
}
A using statement just creates a try/finally with Dispose() calls in the finally. Why not give the developer a unified way of doing disposal and exception handling?
This code should be as follows to ensure timely closing of the connection. Closing just the command doesn't close the connection:
using (SqlConnection con = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
To answer your question, you can do the same in a finally block, but this scopes the code nicely and ensures that you remember to clean up.
There may be no advantage to using a using statement in this case if you're going to have a try/catch/finally block anyway. As you know, the using statement is syntactic sugar for a try/finally that disposes of the IDisposable object. If you're going to have your own try/finally anyway, you can certainly do the Dispose yourself.
This really mainly boils down to style - your team may be more comfortable with using statements or using statements may make the code look cleaner.
But, if the boilerplate the using statement would be hiding is there anyway, go ahead and handle things yourself if that's your preference.
If your code looks like this:
using (SqlCommand cmd = new SqlCommand(...))
{
try
{
/* call stored procedure */
}
catch (SqlException ex)
{
/* handles the exception. does not rethrow the exception */
}
}
Then I would refactor it to use try.. catch.. finally instead.
SqlCommand cmd = new SqlCommand(...)
try
{
/* call stored procedure */
}
catch (SqlException ex)
{
/* handles the exception and does not ignore it */
}
finally
{
if (cmd!=null) cmd.Dispose();
}
In this scenario, I would be handling the exception so I have no choice but to add in that try..catch, I might as well put in the finally clause and save myself another nesting level. Note that I must be doing something in the catch block and not just ignoring the exception.
Elaborating on what Chris Ballance said, the C# specification (ECMA-334 version 4) section 15.13 states "A using statement is translated into three parts: acquisition, usage, and disposal. Usage of the resource is implicitly enclosed in a try statement that includes a finally clause. This finally clause disposes of the resource. If a null resource is acquired, then no call to Dispose is made, and no exception is thrown."
The description is close to 2 pages - worth a read.
In my experience, SqlConnection/SqlCommand can generate errors in so many ways that you almost need to handle the exceptions thrown more than handle the expected behaviour. I'm not sure I'd want the using clause here, as I'd want to be able to handle the null resource case myself.
using isn't about catching exceptions. It's about properly disposing of resources that are outside the view of the garbage collector.
one issue with "using" is that it doesn't handles exceptions.
if the designers of "using" would add "catch" optionally to its syntax like below pseudocode, it would be much more useful:
using (...MyDisposableObj...)
{
... use MyDisposableObj ...
catch (exception)
... handle exception ...
}
it could even have an optional "finally" clause to cleanup anything other than the "MyDisposableObj" allocated at the beginning of the "using" statement... like:
using (...MyDisposableObj...)
{
... use MyDisposableObj ...
... open a file or db connection ...
catch (exception)
... handle exception ...
finally
... close the file or db connection ...
}
still there'll be no need to write code to dispose of MyDisposableObj b/c it'd be handled by using...
How do like that?
Yes you would still need to catch exceptions. The benefit of the using block is you are adding scope to your code. You are saying, "Within this block of code do some stuff and when it gets to the end, close and dispose of resources"
It's not completely necessary at all, but it does define your intentions to anyone else using your code, and it also helps not leaving connections etc open by mistake.
There are a lot of great answers here, but I don't think this has been said yet.
No matter what... the "Dispose" method WILL be called on the object in the "using" block. If you put a return statement, or throw an error, the "Dispose" will be called.
Example:
I made a class called "MyDisposable", and it implements IDisposable and simply does a Console.Write. It always writes to the console even in all these scenarios:
using (MyDisposable blah = new MyDisposable())
{
int.Parse("!"); // <- calls "Dispose" after the error.
return; // <-- calls Dispose before returning.
}
The using statement is actually changed into a try/finally block by the compiler in which the parameter of the using block is disposed of so long as it implements the IDisposable interface. Aside from ensuring the specified objects are properly disposed when they fall out of scope, there is really no error capturing gained by using this construct.
As is mentioned by TheSoftwareJedi above, you will want to make sure both the SqlConnection and SqlCommand objects are disposed of properly. Stacking both into a single using block is a bit messy, and might not do what you think it does.
Also, be mindful of using the try/catch block as logic. It's a code smell that my nose has a particular dislike for, and often used by newbies or those of us in a big hurry to meet a deadline.
FYI, in this specific example, because you're using an ADO.net connection and Command object, be aware that the using statement just executes the Command.Dispose, and the Connection.Dispose() which do not actually close the connection, but simply releases it back into the ADO.net Connection pool to be reused by the next connection.open ... which is good, and the absolutely correct thing to do, bc if you don't, the connection will remain unuseable until the garbage collector releases it back to the pool, which might not be until numerous other connection requests, which would otherwise be forced to create new connections even though there's an unused one waiting to be garbage collected.
I would make my decision on when to and when not to use the using statement dependant on the resource I am dealing with. In the case of a limited resource, such as an ODBC connection I would prefer to use T/C/F so I can log meaningful errors at the point they occurred. Letting database driver errors bubble back to the client and potentially be lost in the higher level exception wrapping is sub optimal.
T/C/F gives you peace of mind that the resource is being handled the way you want it to. As some have already mentioned, the using statement does not provide exception handling it just ensures the resource is destructed. Exception handling is an underuitilised and underestimated language structure that is often the difference between the success and failure of a solution.
If the caller of your function is responsible for dealing with any exceptions the using statement is a nice way of ensuring resources are cleaned up no matter the outcome.
It allows you to place exception handling code at layer/assembly boundaries and helps prevent other functions becoming too cluttered.
Of course, it really depends on the types of exceptions thrown by your code. Sometimes you should use try-catch-finally rather than a using statement. My habit is to always start with a using statement for IDisposables (or have classes that contain IDisposables also implement the interface) and add try-catch-finally as needed.
So, basically, "using" is the exact same as "Try/catch/finally" only much more flexible for error handling.
Minor correction to the example: SqlDataAdapter also needs to be instantiated in a using statement:
using (SqlConnection con = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
con.Open();
DataSet dset = new DataSet();
using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
{
adapter.Fill(dset);
}
this.gridDataSource.DataSource = dset.Tables[0];
}
First, your code example should be:
using (SqlConnection conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
With the code in your question, an exception creating the command will result in the just-created connection not being disposed. With the above, the connection is properly disposed.
If you need to handle exceptions in construction of the connection and command (as well as when using them), yes, you have to wrap the entire thing in a try/catch:
try
{
using (SqlConnection conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
}
catch (RelevantException ex)
{
// ...handling...
}
But you don't need to handle cleaning up conn or cmd; it's already been done for you.
Contrast with the same thing without using:
SqlConnection conn = null;
SqlCommand cmd = null;
try
{
conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString);
cmd = new SqlCommand(reportDataSource, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Year", SqlDbType.Char, 4).Value = year;
cmd.Parameters.Add("#startDate", SqlDbType.DateTime).Value = start;
cmd.Parameters.Add("#endDate", SqlDbType.DateTime).Value = end;
cmd.Connection.Open();
DataSet dset = new DataSet();
new SqlDataAdapter(cmd).Fill(dset);
this.gridDataSource.DataSource = dset.Tables[0];
}
catch (RelevantException ex)
{
// ...handling...
}
finally
{
if (cmd != null)
{
try
{
cmd.Dispose();
}
catch { }
cmd = null;
}
if (conn != null)
{
try
{
conn.Dispose();
}
catch { }
conn = null;
}
}
// And note that `cmd` and `conn` are still in scope here, even though they're useless
I know which I'd rather write. :-)
Related
I have a standard routine for executing SqlCommand with an exception handler. But if an exception is thrown within this routine then I can't make an rollback if this standard routine is called within a transaction. So how can I check that this standard routine is placed inside a transaction or not? What is the proper way? I have googled a lot so far...
Do I have to thrown a new exception in my exception handler for the standard routine for forcing the overall transaction to rollback?
My standard routine looks like:
try
using (SqlConnection con = new SqlConnection(dbCon))
{
using (SqlCommand cmd = new SqlCommand(SQL, con))
{
con.Open();
cmd.CommandTimeout = 600;
cmd.ExecuteScalar();
}
}
}
catch (Exception ex)
{
// do some stuff here
maybe check for existence in a transaction here
}
My overall transaction look like this:
using (SqlConnection con = new SqlConnection(dbCon))
{
con.Open();
string TransactionName = "TransactionName";
using (SqlTransaction sqlTransaction = con.BeginTransaction(TransactionName))
{
try
{
// do some stuff here and call the standard routine here several times...
}
catch (Exception vDBException)
{
DB.getInstance().RollbackTransaction(sqlTransaction, TransactionName);
}
}
}
I have tried to make use of select ##trancount with no success.
I have also tried to check sys.sysprocesses from SQL Server with no success.
I really hope that someone can show me the right direction.
SqlDataReader rdr = null;
con = new SqlConnection(objUtilityDAL.ConnectionString);
using (SqlCommand cmd = con.CreateCommand())
{
try
{
if (con.State != ConnectionState.Open)
con.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(Parameter);
cmd.CommandText = _query;
rdr = cmd.ExecuteReader();
}
catch (Exception ex)
{
throw ex;
}
}
In this above code, sqlconnection is opened inside the managed code. Hence, will the connection object be disposed automatically upon ending the scope of USING?
You have to care about the disposal of SqlConnection, since it's a disposable object. You can try this:
using(var sqlConnection = new SqlConnection(objUtilityDAL.ConnectionString))
{
using (SqlCommand cmd = con.CreateCommand())
{
// the rest of your code - just replace con with sqlConnection
}
}
I suggest you replace the con with a local variable - if there isn't already (it does not evident from the code you have posted). There is no need for using a class field for this purpose. Just create a local variable, it would be far more clear to track it.
You should Dispose every temporary IDisposable instance you create manually, i.e. wrap them into using:
// Connecton is IDisposable; we create it
// 1. manually - new ...
// 2. for temporary usage (just for the query)
using (SqlConnection con = new SqlConnection(objUtilityDAL.ConnectionString)) {
// Check is redundant here: new instance will be closed
con.Open();
// Command is IDisposable
using (SqlCommand cmd = con.CreateCommand()) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(Parameter);
cmd.CommandText = _query;
// Finally, Reader - yes - is IDisposable
using (SqlDataReader rdr = cmd.ExecuteReader()) {
// while (rdr.Read()) {...}
}
}
}
Please, notice that
try {
...
}
catch (Exception ex) {
throw ex;
}
is at least redundant (it does nothing but rethrow the exception, while loosing stack trace) and that's why can be dropped out
In general:
In the .Net framework, nothing gets disposed automatically. Otherwise we wouldn't need the IDisposable interface. The garbage collector can only handle managed resources, so every unmanaged resource must be handled in code in the dispose method.
So as a rule, every instance of every class that is implementing the IDisposable must be disposed either explicitly by calling it's Dispose method or implicitly with the using statement.
As best practice, you should strive to use anything that implements the IDisposable interface as a local variable inside a using statment:
using(var whatever = new SomeIDisposableImplementation())
{
// use the whatever variable here
}
The using statement is syntactic sugar. the compiler translates it to something like this:
var whatever = new SomeIDisposableImplementation();
try
{
// use the whatever variable here
}
finally
{
((IDisposable)whatever).Dispose();
}
Since the finally block as guaranteed to run regardless of whatever happens in the try block, your IDisposable instance is guaranteed to be properly disposed.
With SqlConnection specifically, in order to return the connection object back to the connection pool, you must dispose it when done (the Dispose method will also close the connection, so you don't need to explicitly close it) - So the correct use of SqlConnection is always as a local variable inside the using statement:
using(var con = new SqlConnection(connectionString))
{
// do stuff with con here
}
Here is my code:
public void InsertData()
{
using (SqlConnection connection = new SqlConnection(DBHelper.ConnectionString))
{
using (SqlCommand command = new SqlCommand("Some Simple Insert Query", connection))
{
connection.Open();
command.ExecuteNonQuery();
}
}
}
But I found this code sample:
public void InsertData()
{
SqlConnection connection = new SqlConnection(DBHelper.ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand("Some Simple Insert Query", connection);
command.ExecuteNonQuery();
command.Dispose();
connection.Close();
connection.Dispose();
}
why does the author use
command.Dispose()
and
connection.Dispose();
in their code?
using can only be used on objects that are disposable (which is when they implement the interface IDisposable). Doing so will automatically call Dispose on that instance. However in contrast to call it yourself the using-statement ensures that Dispose is also called when an exception whithin that block occurs. So it´s safer to use that approach.
Your first example is equivalent to this:
try
{
SqlConnection connection = new SqlConnection(DBHelper.ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand("Some Simple Insert Query", connection);
try
{
command.ExecuteNonQuery();
}
finally
{
command.Dispose();
}
}
finally
{
connection.Dispose();
}
You'll have resource leak when exception has been thrown:
public void InsertData()
{
SqlConnection connection = new SqlConnection(DBHelper.ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand("Some Simple Insert Query", connection);
command.ExecuteNonQuery(); // <- imagine that this throws exception
// and so these don't execute at all and you'll have two resources leaked:
// 1. Connection
// 2. Command
command.Dispose();
connection.Close();
connection.Dispose();
}
The reasons of the exception can vary:
1. Insert failed (e.g. invalid field value insertion)
2. User doesn't have privelege required
3. RDMBS Internal error
...
You can emulate using with try .. finally which is wordy:
public void InsertData()
{
SqlConnection connection = null;
try {
connection = new SqlConnection(DBHelper.ConnectionString);
connection.Open();
SqlCommand command = null;
try {
command = new SqlCommand("Some Simple Insert Query", connection);
command.ExecuteNonQuery();
}
finally { // rain or shine, dispose the resource (if it has been created)
if (command != null)
command.Dispose();
}
}
finally { // rain or shine, dispose the resource (if it has been created)
if (connection != null)
connection.Dispose();
}
You don't have to use dispose in your example, because the using block does that for you.
See here: using Statement (C# Reference)
He is using connection.Dispose(); because the person is inexperienced and is writing bad code that is not safe. If a exception is thrown the connection will never be disposed of causing it to remain open till the GC collects the connection maybe minutes or hours later.
The using block is just syntactic sugar for the try/finally Dispose() pattern. This is all explained in the documentation.
Note you can also reduce the indentation in your code:
using (SqlConnection connection = new SqlConnection(DBHelper.ConnectionString))
using (SqlCommand command = new SqlCommand("Some Simple Insert Query", connection))
{
connection.Open();
command.ExecuteNonQuery();
}
In .Net IDisposable and the Dispose method are used to clean up unmanaged resources.
.Net keeps track of managed resources so it can clean them up automatically, but it needs to have some help when dealing with unmanaged resources.
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
https://msdn.microsoft.com/en-us/library/system.idisposable.dispose(v=vs.110).aspx
The using statement is a way to automatically call the Dispose method when you're done using it.
Provides a convenient syntax that ensures the correct use of IDisposable objects.
It'll even get called if an exception is called.
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.
https://msdn.microsoft.com/en-us/library/yh598w02.aspx
The code which isn't using the using statements is incorrect.
It'll work most of the time, but if an exception occurs the unmanaged resources in SqlConnection could be left uncleaned.
As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement.
Okay, I've searched "similar" topics but still haven't come across any answer to what I'm going to ask here.
I have a function that creates multiple sql objects under the System.Data.SqlClient namespace. I've read that the using statement disposes of an object after the using block but the variables declared are readonly. My function reuses some of these variables, so I can't really declare them within a using statement.
Here is the body of my function for clarity. Should I call Dispose on the other objects (command, transaction, reader, etc) or will using recursively dispose of them through the connection object? How should I dispose these objects?
I'm still new to C# (I come from C/C++ background) so please forgive me if the question sounds very ignorant.
public string SignIn(string userId, string password)
{
SqlCommand sqlCommand = null;
SqlTransaction sqlTransaction = null;
string sessionId = "";
using(SqlConnection sqlConnection = new SqlConnection Properties.Settings.Default.SessionManagerDBConnectionString))
{
try
{
sqlConnection.Open();
sqlCommand = sqlConnection.CreateCommand();
sqlCommand.CommandText = "GetUserByUserIdPassword";
sqlCommand.CommandTimeout = 30;
sqlCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parameterUserId = sqlCommand.Parameters.Add("#UserId", SqlDbType.NVarChar, 32);
parameterUserId.Value = userId;
SqlParameter parameterPassword = sqlCommand.Parameters.Add("#Password", SqlDbType.NChar, 64);
parameterPassword.Value = this.GetSHA256Hash(password);
sqlTransaction = sqlConnection.BeginTransaction("SampleTransaction");
// more database activity, execute command, store results in datareader
sqlTransaction.Commit();
sqlConnection.Close();
}
catch (SqlException ex)
{
if(sqlTransaction != null)
sqlTransaction.Rollback();
MessageBox.Show(ex.Number + ":" + ex.Message, ex.Server + ":" + ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
return sessionId;
}
I tried to search for similar questions again and found some closer answers.
Is SqlCommand.Dispose() required if associated SqlConnection will be disposed?
Does SqlCommand.Dispose close the connection?
I suppose I should add a finally clause to my try-catch and call several Dispose methods there for all the sql objects I've created. I hope that suffices or is there a recommended style of doing this?
finally
{
if(sqlCommand != null)
sqlCommand.Dispose();
if(sqlTransaction != null)
sqlTransaction.Dispose();
...
}
I tried putting a using statement within the try-catch block for one of the sqlCommand objects, but if that part of the code aborts when an exception is thrown, the execution jumps down to the catch portion. The using does not dispose that sqlCommand object.
try
{
...
using(sqlCommand = sqlConnection.CreateCommand())
{
sqlCommand.CommandText = "GetUserByUserIdPassword2";
sqlCommand.CommandTimeout = 30;
sqlCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parameterUserId = sqlCommand.Parameters.Add("#UserId", SqlDbType.NVarChar, 32);
parameterUserId.Value = userId;
SqlParameter parameterPassword = sqlCommand.Parameters.Add("#Password", SqlDbType.NChar, 64);
parameterPassword.Value = this.GetSHA256Hash(password);
SqlDataReader reader = sqlCommand.ExecuteReader(CommandBehavior.SingleRow);
// throws exception, no stored procedure "GetUserByUserIdPassword2"
}
...
}
catch() {}
// sqlCommand still accessible at this point because using above was "aborted".
If the object implements IDisposable, then use using. If you need to create a new SqlCommand for some reason then finish one using block and start a new one. Or nest them if you still need access to the first SqlCommand.
You can reuse SqlCommand objects, as long as you haven't got a datareader still open from the command. So, you could create a SqlCommand, set all its properties and execute it, then reset all its properties and execute it again and so on. This does save slightly on the costs of memory allocation, but I think it also reduces the clarity of the code, so it is something I would only do if profiling proved it necessary.
will using recursively dispose of them through the connection object
Of course, using knows nothing about SqlConnections or other ADO.NET objects. All it knows is to call Dispose. Whatever the object being disposed does is what happens.
It happens to be the case that disposing a SqlConnection also disposes of the resources of all readers and commands associated with the connection. You only need to dispose the connection.
I don't know whether this is documented on MSDN but I know it from decompiling the assemblies. For compatibility reasons they can never change this behavior so it is safe to rely on it.
In general, you must call dispose on any object implementing IDisposable. Exception to this rule is when you know for sure that it is safe to not call Dispose. Like in this case.
I think I found the answer!
Even though the sqlCommand object was still accessible in the bottom parts of the code when a nested using statement was skipped by a thrown exception, sqlCommand is still disposed later on. I tested this by actually assigning a function to the disposed event of said sqlCommand object.
The code here is slightly different than above because of the transaction object requirement. But the logic is essentially the same.
try
{
using(sqlCommand = new SqlCommand("GetUserByUserIdPassword2", sqlConnection, sqlTransaction))
{
sqlCommand.CommandTimeout = 15;
sqlCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parameterUserId = sqlCommand.Parameters.Add("#UserId", SqlDbType.NVarChar, 32);
parameterUserId.Value = userId;
SqlParameter parameterPassword = sqlCommand.Parameters.Add("#Password", SqlDbType.NChar, 64);
parameterPassword.Value = this.GetSHA256Hash(password);
sqlCommand.Disposed += new System.EventHandler(this.sqlCommand_Disposed);
SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(CommandBehavior.SingleRow);
// exception thrown, no sored proc "GetUserByUserIdPassword2"
sqlDataReader.Close();
}
}
catch(...) {}
...
private void sqlCommand_Disposed(object sender, EventArgs e)
{
MessageBox.Show("sqlCommand has been disposed");
}
So, basically, even if a nested using statement is "aborted" by a thrown exception within the try block, and execution is skipped down to the catch block, the Dispose method is still called for that object after the function exits (or when the variable goes out of scope).
I presume this behavior is the same for any number of nested using statements.
in CSharp, using is a special keyword which have different acts in code..
if you put using to top of the codepage then using acts as c++ ' s Include or VB (and some other script langs') Import
if you write a "using" which follows by a paranthesis then it acts like an alias of Dispose() method of CSharp.. or Destructor tilda of c++ or free() method of plain c..
About SQL Connection.. Best way is first Close() the connection (so with this, connection is still alive -actually just ready to use- but null.. return to wait new order in connection pool.. ) and then dispose if you need..
if you have still problems and suspected that calling the Dispose() method not enough to free the resources
then you can use Garbage Collector's Collect() static method to force the garbage collection
But not so much recommended by Microsoft because of face with accidental garbage collection problems (i.e. you collect the form but need some variable from that form )
in example of usage :
public void Dispose (bool ForceToCollect )
{
if (ForceToCollect)
GC.Collect (0, GCCollectionMode.Forced );
}
In Gc.Collect() method you can set which group of data memory freed with first option where is int..if you plan to free resources of the last group - means last created group of items, as an example last created form instance and its all child controls - then int should be 0; the one which is 1 before the last created then should be 1 and so on..
Hope this helps..
This question already has answers here:
try/catch + using, right syntax
(9 answers)
Closed 8 years ago.
The following 2 sets of codes produce same results, but I'm wondering which of these is the correct way of wrapping with the try...catch block. What's the difference between the 2 of them?
Edited: Which of this will properly capture the error, and also to make sure the connection will be closed even if there is an exception.
1
try
{
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = new SqlCommand("Drop Table sometable", conn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
}
catch
{
//
}
2
using (SqlConnection conn = new SqlConnection(connString))
{
try
{
SqlCommand cmd = new SqlCommand("Drop Table sometable", conn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
catch
{
//
}
}
The difference is that in the #2 SqlConnection conn object will be disposed after the catch block will be finished. In #1 your connection will be disposed and than you will end up in the catch block.
Both are fine, depended on if you want to catch an error when opening the connection, and then of course you need to close the connection when you are done with it. usually closing earlier is better.
the difference is:
if you use code 2, and your connString you use in your using statement is invalid, it will throw an exception, because it is not in the try catch block.
in code 1, it will just catch that exception. but you will not be able to use your SqlConnection in the catch block
I thik that you are aware of exception handling.
We write all of our codes inside the catch block that can arise suspicious/unknown behavior to our applications. In that case the catch block handles the suspicious behavior of our application.
In context to your above two block of codes ....
For the first one- any exception caused by any one statement of your codes will be handled by catch block.
But for second one- exception caused by "using (SqlConnection conn = new SqlConnection(connString))" statement cannot be handled by your catch block, because it is outside of the try block. To test this just place some false connection string in sqlconnection.
Hope this will gives you better understanding for your scenario.
The using statement is a syntactic shortcut to represent a try/catch/finally. You could right your code as below, and would have the same effect as your examples above.
SqlConnection conn
try
{
conn = new SqlConnection(connString)
SqlCommand cmd = new SqlCommand("Drop Table sometable", conn);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
catch
{
//
}
finally
{
if(conn != null)
{
conn.Dispose()
}
}