In the IDisposable.Dispose
method is there a way to figure out if an exception is being thrown?
using (MyWrapper wrapper = new MyWrapper())
{
Now, in 2017, this is the generic way to do it, incl handling rollback for exceptions.
public static T WithinTransaction<T>(this IDbConnection cnn, Func<IDbTransaction, T> fn)
{
cnn.Open();
using (var transaction = cnn.BeginTransaction())
{
try
{
T res = fn(transaction);
transaction.Commit();
return res;
}
catch (Exception)
{
transaction.Rollback();
throw;
}
finally
{
cnn.Close();
}
}
}
and you call it like this:
cnn.WithinTransaction(
transaction =>
{
var affected = ..sqlcalls..(cnn, ..., transaction);
return affected;
});
In my case, I wanted to do this to log when an microservice crashes. I already have in place a using
to properly clean up right before an instance shut down, but if that's because of an exception I want to see why, and I hate no for an answer.
Instead of trying to make it work in Dispose()
, perhaps make a delegate for the work you need to do, and then wrap your exception-capturing in there. So in my MyWrapper logger, I add a method that takes an Action / Func:
public void Start(Action<string, string, string> behavior)
try{
var string1 = "my queue message";
var string2 = "some string message";
var string3 = "some other string yet;"
behaviour(string1, string2, string3);
}
catch(Exception e){
Console.WriteLine(string.Format("Oops: {0}", e.Message))
}
}
To implement:
using (var wrapper = new MyWrapper())
{
wrapper.Start((string1, string2, string3) =>
{
Console.WriteLine(string1);
Console.WriteLine(string2);
Console.WriteLine(string3);
}
}
Depending on what you need to do, this may be too restrictive, but it worked for what I needed.
It is not only possible to find out if an exception was thrown when a disposable object is disposed you can even get your hands on the exception that was thrown inside the finally clause with a little magic. My Tracing library of the ApiChange tool employs this method to trace exceptions inside a using statement. More infos how this works can be found here.
Yours, Alois Kraus
You can extend IDisposable
with method Complete
and use pattern like that:
using (MyWrapper wrapper = new MyWrapper())
{
throw new Exception("Bad error.");
wrapper.Complete();
}
If an exception is thrown inside the using
statement Complete
will not be called before Dispose
.
If you want to know what exact exception is thrown, then subscribe on AppDomain.CurrentDomain.FirstChanceException
event and store last thrown exception in ThreadLocal<Exception>
variable.
Such pattern implemented in TransactionScope
class.
You can do this buy implementing the Dispose method for the "MyWrapper" class. In the dispose method you can check to see if there is an exception as follows
public void Dispose()
{
bool ExceptionOccurred = Marshal.GetExceptionPointers() != IntPtr.Zero
|| Marshal.GetExceptionCode() != 0;
if(ExceptionOccurred)
{
System.Diagnostics.Debug.WriteLine("We had an exception");
}
}