Does a transaction Rollback() have any chance to throw an exception? - c#

Question related to managing trasactions with EF Core:
Does an IDbContextTransaction.Rollback() have any chance to return an exception, so that it could ever make sense to place it inside a try block?
i.e.
try
{
//...
if(condition)
transaction.Commit();
else
throw methodReturn.Exception;
}
catch (Exception e)
{
try // Does this try make any sense?
{
transaction.Rollback();
}
catch
{
// Log
}
throw e;
}
PD: In this specific situation it is not possible to embed the transaction into a using statement, so a manual .Rollback() call is required in the real code.

Most of the times it is not until:
Deadlock Detection
No Internet Connectivity
Logically and Physically consistent connection
Shutdown, Power failure, Unexpected termination
To tackle these situations, you can:
Use the Xact_Abort setting. When SET XACT_ABORT is ON, if a Transact-SQL statement raises a run-time error, the entire transaction is terminated and rolled back.
When SET XACT_ABORT is OFF, in some cases only the Transact-SQL statement that raised the error is rolled back and the transaction continues processing. Depending upon the severity of the error, the entire transaction may be rolled back even when SET XACT_ABORT is OFF. OFF is the default setting.
Catch and handle the error, and specify a rollback within the error handling

Related

How to know if transaction scope was successful or not

I need to know if my transaction scope was successful or not. As in if the records were able to be saved in the Database or not.
Note: I am having this scope in the Service layer, and I do not wish to include a Try-Catch block.
bool txExecuted;
using (var tx = new TransactionScope())
{
//code
// 1 SAVING RECORDS IN DB
// 2 SAVING RECORDS IN DB
tx.Complete();
txExecuted = true;
}
if (txExecuted ) {
// SAVED SUCCESSFULLY
} else {
// NOT SAVED. FAILED
}
The commented code will be doing updates, and will probably be implemented using ExecuteNonQuery() - this returns an int of the number of rows affected. Keep track of all the return values to know how many rows were affected.
The transaction as a whole will either succeed or experience an exception when it completes. If no exception is encountered, the transaction was successful. If an exception occurs, some part of the transaction failed; none of it took place
By considering these two facts (records affected count, transaction exception or no) you can know if the save worked and how many rows were affected
I didn't quite understand the purpose of txExecuted- if an exception occurs it will never be set and the if will never be considered. The only code that will thus run is the stuff inside if(true). I don't see how you can decide to not use a try/catch and hope to do anything useful with a system that is geared to throw an exception if something goes wrong; you saying you don't want to catch exceptions isn't going to stop them happening and affecting the control flow of your program
To be clear, calling the Complete() method is only an indication that all operations within the scope are completed successfully.
However, you should also note that calling this method does not
guarantee a commit of the transaction. It is merely a way of informing
the transaction manager of your status. After calling this method, you
can no longer access the ambient transaction via the Current property,
and trying to do so results in an exception being thrown.
The actual work of commit between the resources manager happens at the
End Using statement if the TransactionScope object created the
transaction.
Since you are using ADO.NET, ExecuteNonQuery will return the number of rows affected. You can do a database lookup after the commit and outside of the using block.
In my opinion, its a mistake not to have a try/catch. You want to catch the TransactionAbortedException log the exception.
try
{
using (var scope = new TransactionScope())
{
using (var conn = new SqlConnection("connection string"))
{
}
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
}
catch (TransactionAbortedException ex)
{
// log
}

Should we put try catch with function if we just want to log the exception?

In asp.net application, all the exception that occurs and are not inside try catch can be handled by application_error.
If we just need to log the exception along with its stack trace, and we need not make any other decision/logic inside catch, why should we put try catch at application/bl or dal layer functions? Is there any reason to put try/catch with every database call function?
For example we have hundreds of function in DAL layer that executes following code:
try
{
//open db connection, execute stored procedure
}
catch
{
//log error
}
In case we get any exception from stored procedure OR in opening database connection, we get an exception but we are not doing anything except for logging these errors. We don't have very critical data-storage/retrieval requirement. We are logging error just to be alerted and fix it later. Is this correct to put catch in every such function?
Using try and catch is not for logging purposes only, especially when dealing with database connections.
An exception means that something wasn't completed. If something wasn't completed, your business process failed. If your business process failed, you need to know about it and handle it within the scope of that code, not application_error. Each error should be handled within the scope it was generated from. application_error should be your last fallback, and theoretically should never be reached.
Sure, you can use it for logging, but also for closing your DB connection (which was probably opened before the exception occurred and be left forever open), informing your users that an exception occured, and for data recovery, alternating your process to deal with the exception or preparing it for a retry.
So, taking your posted template, good code handling should look like this:
try
{
//open db connection, execute stored procedure
}
catch
{
// Inform the user
// Alternate your process or preparing for retry
// log error
}
finally
{
// Close the DB connection
}
One should use try/catch blocks only in places where you can meaningfully handle an exception. However, "meaningful handling " includes providing good error messages.
If your catch block simply logs the exception with no additional context, then such block could be replaced with a top-level handler (like application_error) that does the same thing.
If, however, you log additional information available only at the point of invocation, then having a catch block is entirely justified: it enhances the experience by providing better diagnostics, which is a perfectly legitimate goal.

Exception Handling error when saving to database

Iam a newbie who needs help. When saving to a database, i get the following error:
A first chance exception of type 'System.Data.SqlServerCe.SqlCeException' occurred in (name of my application)
Please help me with steps to solve this one. Thank you in advance.
First chances exceptions will be shown if you have your Visual Studio settings set so that every CLR exceptions gets reported. This will include exceptions you actually handle.
In Visual Studio's menu, go to Debug > Exceptions and uncheck the Thrown option for Common Language Runtime Exceptions.
Of course that won't make the actual exception go away but you'll be allowed to handle it as you want:
try
{
// do your query
// commit current transaction if possible/necessary
}
catch (SqlCeException ex)
{
// handle exception here and rollback current transaction if possible/necessary
}
finally
{
// ensure proper disposal of any commands and connections you have
}
It goes without saying that you must ensure your query is properly written and that the server objects it tries to work with exists. You generally won't want to handle cases where a comma is missing or a field is not found, for instance. Exception handling must be for exceptional situations your code cannot control, like a faulted connection, a server malfunction, etc.
First of all you might want to check whehter your SQL query is syntactically correct.
Secondly you might want to read about how to handle exceptions in MSDN http://msdn.microsoft.com/en-us/library/0yd65esw.aspx with try-catch statement.
A small example looks like this.
try
{
// ... code which throws exception
}
catch (SqlCeException e)
{
// ... exception handling, e.g. logging, rolling back data,
// telling the user something went wrong, you name it
}
Last but not least you might want to debug your application step by step to see what is causing the error and what the actual SQL Query is throwing the exception.

SqlTransaction causing application crash on error?

Here's some background: Periodically our site will crash to the point of having to restart IIS; this almost always happens within an hour of patching a DLL (we use a Web Site project, not a Web Application project, so each ASPX page is a separate DLL).
In doing some research I have found that our homebrew DAL can, while debugging, cause the built-in webserver with Visual Studio to actually stop working and be shut down if it encounters a SQL error in a stored procedure (I mean it will not only throw an exception that is displayed in the browser, it will actually say that the web server has experienced an error and needs to close!)
In digging further the error seems to be related to the use of transactions for everything (including Select statements) in the DAL. What seems to happen is this:
Tries to execute stored procedure, stored procedure fails due to missing/invalid column or other error.
Application code catches the error and rethrows it (bad, yes, but I didn't write this).
Transaction tries to commit despite the exception, gets a NullReferenceException on the transaction.Commit() line (seems to be on the Connection property because there is a transaction object). Also this NullRef seems like it cannot be caught (I tried a demo that force crashed with an invalid Sproc and the NullRef was never caught even though outputting the error gave its type as System.NullReferenceException)
Transaction throws error that say something like "The transaction has completed and is no longer usable".
??? but the VS web server crashes. Debugging this part seems to hang on the above exception, never leaving the method.
Now, I don't know if this is what causes IIS to crash, but it seems quite suspicious and it's a glaring error in any event.
Having not dealt with transactions before and having only the basic idea of them, my first question is why the transaction is still trying to commit after an exception is being thrown? My second question is how to fix the failing commit and presumably infinite looping of exceptions until the server dies. Wouldn't it make sense to add something like this (the method takes a SqlTransaction parameter named transaction):
catch (SqlException se)
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
Would that small change fix the constant exception loop that I think is crashing IIS? The DAL itself is extremely brittle and is used concretely in hundreds of files so I can't rewrite it from scratch correctly.
EDIT The entire code block is this (again, legacy code - uses the old microsoft data access block helper):
public static DataSet ExecuteDatasetStoredProc(SqlConnection conn, String storedProcName, SqlTransaction transaction, params SqlParameter[] storedProcParms)
{
try
{
// Execute the stored proc
if (transaction != null)
{
return SqlHelper.ExecuteDataset(transaction, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
else
{
return SqlHelper.ExecuteDataset(conn, CommandType.StoredProcedure, storedProcName, storedProcParms);
}
}
catch (SqlException se)
{
throw new ApplicationException("Error calling " + storedProcName + ". " + se.Message, se);
}
}
However, if the catch block executes the transaction still tries to commit and this seems to be causing the hangups.
also Change your if you wrap your Transactional code in a try catch
Try
{
// your code that you assign and execute the SQl
}
catch (SQLException sqlex)
{
try
{
//try to do the rollback here.. don't always assume the commit or rollback will work
}
catch (Your SQL Exception ex)
{
}
}

Use case for try-catch-finally with both catch and finally

I understand how try-catch works and how try-finally works, but I find myself using those (usually) in two completely different scenarios:
try-finally (or using in C# and VB) is mostly used around some medium-sized code block that uses some resource that needs to be disposed properly.
try-catch is mostly used either
around a single statement that can fail in a very specific way or
(as a catch-all) at a very high level of the application, usually directly below some user interface action.
In my experience, cases where a try-catch-finally would be appropriate, i.e., where the block in which I want to catch some particular exception is exactly the same block in which I use some disposable resource, are extremely rare. Yet, the language designers of C#, VB and Java seem to consider this to be a highly common scenario; the VB designers even think about adding catch to using.
Am I missing something? Or am I just overly pedantic with my restrictive use of try-catch?
EDIT: To clarify: My code usually looks like this (functions unrolled for clarity):
Try
do something
Aquire Resource (e.g. get DB connection)
Try
do something
Try
do something that can fail
Catch SomeException
handle expected error
do something else...
Finally
Close Resource (e.g. close DB connection)
do something
Catch all
handle unexpected errors
which just seems to make much more sense than putting any of the two catches on the same level as finally just to avoid indentation.
A quote from MSDN
A common usage of catch and finally
together is to obtain and use
resources in a try block, deal with
exceptional circumstances in a catch
block, and release the resources in
the finally block.
So to make it even more clear, think of the code that you want to run, in 99% of the cases it runs perfectly well but somewhere in the chunk there might occure an error, you don't know where and the resources created are expensive.
In order to be 100% sure that the resources are disposed of, you use the finally block, however, you want to pin-point that 1% of cases where the error occures, therefore you might want to set up logging in the catch-ing-section.
That's a very common scenario.
Edit - A Practical Example
There is some good examples here: SQL Transactions with SqlTransaction Class. This is just one of the many ways to use Try, Catch & Finally and it demonstrates it very well, even though a using(var x = new SqlTranscation) might be efficient some times.
So here goes.
var connection = new SqlConnection();
var command = new SqlCommand();
var transaction = connection.BeginTransaction();
command.Connection = connection;
command.Transaction = transaction;
Here comes the more interesting parts
///
/// Try to drop a database
///
try
{
connection.Open();
command.CommandText = "drop database Nothwind";
command.ExecuteNonQuery();
}
So let's imagine that the above fails for some reason and an exception is thrown
///
/// Due to insufficient priviligies we couldn't do it, an exception was thrown
///
catch(Exception ex)
{
transaction.Rollback();
}
The transaction will be rolled back! Remember, changes you made to objects inside the try/catch will not be rolled back, not even if you nest it inside a using!
///
/// Clean up the resources
///
finally
{
connection.Close();
transaction = null;
command = null;
connection = null;
}
Now the resources are cleaned up!
Not an answer to your question, but a fun fact.
The Microsoft implementation of the C# compiler actually cannot handle try-catch-finally. When we parse the code
try { Foo() }
catch(Exception e) { Bar(e); }
finally { Blah(); }
we actually pretend that the code was written
try
{
try { Foo(); }
catch(Exception e) { Bar(e); }
}
finally { Blah(); }
That way the rest of the compiler -- the semantic analyzer, the reachability checker, the code generator, and so on -- only ever has to deal with try-catch and try-finally, never try-catch-finally. A bit of a silly early transformation in my opinion, but it works.
Example:
Try
Get DB connection from pool
Insert value in table
do something else...
Catch
I have an error... e.g.: table already contained the row I was adding
or maybe I couldn't get the Connection at all???
Finally
if DB connection is not null, close it.
You can't really get a more "common" example. Pity that some people still forget to put the close connection in the Finally, where it belongs, instead of in the Try block... :(
I often write code that looks like this:
Handle h = ...
try {
// lots of statements that use handle
} catch (SomeException ex) {
// report exception, wrap it in another one, etc
} catch (SomeOtherException ex) {
// ...
} finally {
h.close();
}
So maybe you are just being overly pedantic ... e.g. by putting a try / catch around individual statements. (Sometimes it is necessary, but in my experience you don't usually need to be so fine-grained.)
There is nothing wrong with nesting try/catch/finally blocks. I actually use this quite often. I.e. when I use some resource that needs to be disposed or closed but I want only a single catch block around a larger code unit that needs to be aborted if some error occurs inside it.
try {
// some code
SomeResource res = new SomeResource();
try {
res.use();
} finally {
res.close();
}
// some more code
} catch( Exception ex ) {
handleError( ex );
}
This closes the resource as early as possible in either case (error or not) but still handles all possible errors from creating or using the resource in a single catch block.
I think you are quite right. From the .Net Framework Design Guidelines, written by some of the top architects at Microsoft:
DO NOT overcatch. Exceptions should
often be allowed to propagate up the
call stack.
In well-written code, try-finally [or
using] is far more common than
try-catch. It might seem
counterintuitive at first, but catch
blocks are not needed in a surprising
number of cases. On the other hand,
you should always consider whether
try-finally [or using] could be of use
for cleanup.
page 230 section 7.2
I would nearly always use try-catch-finaly in cases where you need to dispose something in all cases and you use the case to log the error and/or inform the user.
How about something like:
Dim mainException as Exception = Nothing
Try
... Start a transaction
... confirm the transaction
Catch Ex as Exception
mainException = Ex
Throw
Finally
Try
... Cleanup, rolling back the transaction if not confirmed
Catch Ex as Exception
Throw New RollbackFailureException(mainException, Ex)
End Try
End Try
Assuming here that the RollbackFailureException includes an "OriginalException" field as well as "InnerException", and accepts parameters for both. One doesn't want to hide the fact that an exception occurred during the rollback, but nor does one want to lose the original exception which caused the rollback (and might give some clue as to why the rollback happened).
Another use would be to dispose a file handle to an e-mail attachment when using the System.Web.Mail mail objects to send e-mail. I found this out when I had to programatically open a Crystal Report, save it to disk, attach it to an e-mail, and then delete it from disk. An explicit .Dispose() was required in the Finally to make sure I could delete it, especially in the event of a thrown exception.
In my experience, cases where a try-catch-finally would be appropriate, i.e., where the block in which I want to catch some particular exception is exactly the same block in which I use some disposable resource, are extremely rare. Yet, the language designers of C#, VB and Java seem to consider this to be a highly common scenario; the VB designers even think about adding catch to using.
you:
try {
//use resource
} catch (FirstException e) {
// dispose resource
// log first exception
} catch (SecondException e) {
// dispose resource
// log first exception
} catch (ThirdException e) {
// dispose resource
// log first exception
}
me:
try {
//use resource
} catch (FirstException e) {
// log first exception
} catch (SecondException e) {
// log first exception
} catch (ThirdException e) {
// log first exception
} finally {
// dispose resource
}
feel defference?)

Categories

Resources