Question
I am currently implementing a UOW pattern and have come upon a weird behaviour for exception handling, which is hindering my progress.
My UOW structure looks the following:
public abstract class UnitOfWork : IDisposable {
public virtual void Save() {
if (_madeAction) ThrowInvalidCall();
_madeAction = true;
}
public virtual void Cancel() {
if (_madeAction) ThrowInvalidCall();
_madeAction = true;
}
public virtual void Dispose() {
if (!_madeAction) {
Cancel();
throw new UnitOfWorkAborted("Unit of work was aborted and automatically rolled back!");
}
}
private bool _madeAction = false;
private void ThrowInvalidCall() => throw new InvalidOperationException($"{nameof(Save)} or {nameof(Cancel)} can only be called once in a unit of work!");
}
[Serializable]
public class UnitOfWorkAborted : Exception {
public UnitOfWorkAborted() { }
public UnitOfWorkAborted(string message) : base(message) { }
public UnitOfWorkAborted(string message, Exception inner) : base(message, inner) { }
}
public interface IUnitOfWorkFactory {
UnitOfWork CreateNew();
}
I am expecting to use this UOW as follows:
try {
using (var uow = uowFactory.CreateNew()) {
// Do some operation
throw new InvalidCastException(); // Oh, something went wrong.
uow.Save();
}
} catch (UnitOfWorkAborted ex) {
// Handle exception
}
The problem obviously is, that the excpetion will never be handled by my try/catch clause as it only handles UnitOfWorkAborted which is only thrown after the InvalidCastException.
My question is, is there any way I can use my UOW how I expect it to work? (I'd like to replicate this behaviour -> TransactionScope)
I want to keep the code for creating a UOW and managing it as simple as possible.
If possible, I would love to even have the actual exception as the inner exception of UnitOfWorkAborted.
Observations/Attempts
1. Instead of catching the UnitOfWorkAborted I can catch all Exceptions and cast it to UnitOfWorkAborted.
try {
using (var uow = uowFactory.CreateNew()) {
throw new InvalidCastException();
uow.Save();
}
} catch (Exception ex) {
UnitOfWorkAborted uowEx = ex as UnitOfWorkAborted;
if (uowEx is null) throw ex;
// Handle exception
}
Cons:
I will need to cast the exception to UnitOfWorkAborted and this adds code that should be avoidable because:
What is try/catch then even for when not for specifying which exception to handle? This approach just feels.. ugh.
2. Add a catch clause for Exception.
try {
using (var uow = uowFactory.CreateNew()) {
throw new InvalidCastException();
uow.Save();
}
} catch (UnitOfWorkAborted ex) {
// Handle exception
} catch (Exception ex) {
throw ex;
}
I discovered this through experimentation, it works perfectly fine. Would it be possible to get a side-explanation on the details for why this works, I would be incredibly interested to know. Either way, the syntax is incredibly misleading, even worse than with the first attempt, and this is no option of course, just, look at it.
Are these two attempts really my only options on solving this problem?
I ended up using the callback method suggested by Jeremy Lakeman in the comments, which ended up working perfectly fine, with the bonus of catching inner exceptions.
Related
Here What I want to do, but do not know if it will work or if there is a better way:
if (condition1){
try {
Block1;
}
} else if (condition2){
try {
Block2;
}
}
catch(ExceptionType1 ex) { process;}
catch(ExceptionType2 ex) { process;}
catch(Exception) {throw;}
So is that the best way this could be done?
This can do what you want.
try {
if (condition1) {
Block1;
} else if (condition2) {
Block2;
}
}
catch(ExceptionType1 ex) { process;}
catch(ExceptionType2 ex) { process;}
catch(Exception) {throw;}
If not, try to put a clear detailed example.
There is no syntax to support exactly, but you might be able to get a similar effect by defining exception classes, and purposely throwing those exceptions in block1 and block2, either through separate try/catches or if/conditonal statements (checking for null, "", etc.)
Here's an example of an exception class behind defined, taken from here
[Serializable()]
public class InvalidDepartmentException : System.Exception
{
public InvalidDepartmentException() : base() { }
public InvalidDepartmentException(string message) : base(message) { }
public InvalidDepartmentException(string message, System.Exception inner) : base(message, inner) { }
// A constructor is needed for serialization when an
// exception propagates from a remoting server to the client.
protected InvalidDepartmentException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
In the logic that you want to throw the exceptions in, you just need to define and throw the Exception class you defined. This can be done in a separate catch block, as well
System.ArgumentException argEx = new System.ArgumentException("Index is out of range", "index", ex);
throw argEx;
I'm not sure what you try to achieve with your structure in detail. But I see currently no issue in wrapping the whole statement block into a single try-block #AbdelAzizAbdelLatef mentioned and catch different exception types.
Maybe you can think about, to move your both code blocks (Block1 & Block2) into own functions/methods and perform a specific exception handling there and maybe returning some status code from each new block function. This would be a more clean code approach.
I have not come across any Question/Solution in Stackoverflow for this question which has got some high number of votes.
So I thought I will ask it again here.
How to handle or what to do if there is an Exception in Dispose() method.
Shall we Log it or if I Rethrow the Exception, will it get Rethrown. I might want to Rethrow it so that I come to know I made a mistake somewhere in my Dispose()
Even If we suppose it does get Rethrown, will it be a good practice to rethrow it?
In most (but not all) cases, your exception handlers should be at the code entry point.
Just let the exception bubble up, like this.
public static class Program
{
public static void Main()
{
try
{
using (new QuestionableCodeAtBest()) {}
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
}
class QuestionableCodeAtBest : IDisposable
{
const int TotalHands = 2;
public void Dispose()
{
var handsThatAreClapping = 0;
Console.WriteLine($"What is the sound of no hands clapping?: {TotalHands / handsThatAreClapping}");
}
}
I got this class which raises same type of exception, how do i capture this exception and display appropriate error message. Here is what i do now.
public bool ChangePassword(oldPassword,newPassword)
{
if(oldPassword != savedInDatabase)
{
throw new ArgumentException("Your old password is not same as one saved in our database")
}
if(string.IsNullOrEmpty(oldPassword) || string.IsNullOrEmpty(newPassword))
{
throw new ArgumentException("Your old or new password is empty of null");
}
}
and i do the below,
try
{
}
catch(ArgumentException ex)
{
if(ex.Message.contains("Your old or"))
{
messagebox.show("Either your old or new password is empty or null")
}
...
}
Your example does not really justify custom exceptions. I say just display the original message.
However, if you really want to go down the path of custom exceptions, then another option is to create a single custom exception that takes an enum with all the different options, like such:
public class PasswordException : Exception
{
public PasswordException(PasswordResult result) : base() { }
public PasswordException(PasswordResult result, string message) : base(message) { }
public PasswordException(PasswordResult result, string message, Exception innerException) : base(message, innerException) { }
}
public enum PasswordResult
{
Success = 0,
PasswordMismatch,
PasswordEmpty,
// and so forth
}
You might consider throwing different exception types. If you wished to stick with the library exception types an ArgumentNullException would be appropriate if the old or new password is null or empty. Alternatively you may consider defining your own exception types with a more specific error (perhaps similar to FaultExceptions in WCF), or including a resource identifier in your custom exception (to ensure I18N compatible):
public class ResourceableException : Exception
{
public string ResourceKey { get;set; }
}
Then used like so:
try { ... }
catch (ResourceableException e)
{
messagebox.Show(ResourceManager.GetResource(e.ResourceKey));
}
You can create custom exceptions like this:
public class PasswordEmptyOrNullException : Exception
{
public PasswordEmptyOrNullException(string message)
: base(message)
{
}
}
public class OldPasswordNotFoundException : Exception
{
public OldPasswordNotFoundException(string message)
: base(message)
{
}
}
They can then be used like this:
throw new PasswordEmptyOrNullException("A message");
Then you can handle them in a try catch statement like this:
try
{
}
catch (PasswordEmptyOrNullException ex)
{
// Do stuff
}
catch (OldPasswordNotFoundException ex)
{
// Do stuff
}
So you can handle different types of exceptions in different ways. Hope that's what you were looking for.
I am fully aware that what I am about to ask is not good practice... but:
Let's say I have a class containing a function that I want to always return a value, but store any exceptions that might occur for later processing. Something Like:
public Exception _error { get; set; }
public bool IsValid()
{
try
{
//do something here to cause exception
return true;
}
catch (Exception ex)
{
_error = ex;
return false;
}
}
Now that I have stored the exception, is it at all possible to throw the exception from an outside method while maintaining both the original stack trace and exception type?
throw _error; //lose stack trace
throw new Exception("", _error) //lose type
Thanks for looking or answering.
EDIT:
Thanks to some additional points, I realize that the below idea only takes away information and doesn't really add or simplify the situation. Thanks again to everyone.
After pondering Pieter's answer and comments, I'm now wondering if making a wrapper Exception class like the below could be a partial solution. This overrides as much of the exception as possible to make the New exception look like its innerexception, including the stacktrace.. dirty I know, but interesting:
public class ExceptionWrapper : Exception
{
private Exception _innerException;
public ExceptionWrapper(Exception ex) : base("", ex)
{
_innerException = ex;
this.Source = ex.Source;
this.HelpLink = ex.HelpLink;
}
public override string StackTrace
{
get
{
return _innerException.StackTrace;
}
}
public override System.Collections.IDictionary Data
{
get
{
return _innerException.Data;
}
}
public override string Message
{
get
{
return _innerException.Message;
}
}
public new Exception InnerException
{
get
{
return _innerException.InnerException;
}
}
}
No, this is not possible.
However, you normally solve this is by wrapping the exception in a new exception:
throw new MyException("Wrapper", _error);
This does maintain the stack trace of _error, but you do get a new exception. Your solution in your second example is the correct way of handling these cases.
Consider using reflection to create a wrapper exception of the correct type (Activator.CreateInstance) and calling the constructor that will accept the inner exception you have stored.
For example:
[Test]
public void test()
{
Exception ex = new ArgumentNullException();
Exception wrapped = (Exception)Activator.
CreateInstance(ex.GetType(), "wrapped", ex);
Type expectedType = typeof(ArgumentNullException);
Assert.IsInstanceOf(expectedType, wrapped, "Is ArgumentNullException.");
Assert.AreEqual(ex, wrapped.InnerException, "Exception is wrapped.");
}
Update
In order to mitigate the constructor issue, you could consider using the default constructor (should be there for an exception that follows design guidelines, but not mandatory) and then patching up the new instance by setting its fields via reflection.
I agree the approach is highly "meh" it's more an exploration of an idea. I wouldn't recommend it.
The exception design guidelines require a default constructor, so this sort of behaviour may go on in the framework somewhere anyway. Perhaps for some sort of icky serialization\deserialization of exceptions across some sort of communications boundary?
It seems that .net-4.5 added a new API for capturing stack/info about exceptions and rethrowing them in different contexts. This is called ExceptionDispatchInfo. It is useful if you find yourself needing more control over running tasks indirectly, like if you do manual thread management for jobs or Task does not exactly fit your needs. In your example, it should look like this:
public ExceptionDispatchInfo _error { get; private set; }
public bool IsValid()
{
try
{
//do something here to cause exception
return true;
}
catch (Exception ex)
{
_error = ExceptionDispatchInfo.Capture(ex);
return false;
}
}
/// <summary>Throw underlying exception if invalid.</summary>
public void AssertWasValid() => _error?.Throw();
Now, it doesn’t preserve the original caller. The displayed stack trace shows the calls from the original try block into the code in there, a statement breaking the original and new parts of the stack, and then the calls into ExceptionDispatchInfo.Throw() itself as the new part of the shown stack. This seems similar to how traces with async code look. If you care about the original caller, seems this won’t work. But if you care about getting the line/method that threw the exception, this should be sufficient.
I have two functions that have different enough logic but pretty much the same exception handling:
public void DoIt1 // DoIt2 has different logic but same exception handling
{
try
... DoIt1 logic
catch (MySpecialException myEx)
{
Debug.WriteLine(myEx.MyErrorString);
throw;
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
throw;
}
}
It is not possible to use a single entry point for DoIt1 and DoIt2, because they are called in from outside.
Is Copy/Pase (for the exception block) the best approach?
It depends... if there is that much commonality, you could pass in the thing to do as a parameter - either as an interface or a delegate:
void Foo(Action thingToDo) {
if(thingToDo == null) throw new ArgumentNullException("thingToDo");
try {
thingToDo();
} catch {...} // lots of
}
And call as:
Foo(delegate { /* logic A */ });
Foo(delegate { /* logic B */ });
Try:
public static class Catching<TException> where TException : Exception
{
public static bool Try<T>(Func<T> func, out T result)
{
try
{
result = func();
return true;
}
catch (TException x)
{
// log exception message (with call stacks
// and all InnerExceptions)
}
result = default(T);
return false;
}
public static T Try<T>(Func<T> func, T defaultValue)
{
T result;
if (Try(func, out result))
return result;
return defaultValue;
}
}
Example:
int queueSize = Catching<MyParsingException>
.Try(() => Parse(optionStr, "QueueSize"), 5);
If Parse throws a MyParsingException, queueSize will default to 5, otherwise the returned value from Parse is used (or any other exception will propagate normally, which is usually what you want with an unexpected exception).
This helps to avoid breaking up the flow of the code, and also centralises your logging policy.
You can write specialised versions of this kind of exception wrapping for special cases, e.g. catching a particular set of three exceptions, or whatever.
For the extreme end of the spectrum of possible solutions, check out Aspect-Oriented-Programming techniques, and tools such as PostSharp or Microsoft Policy Injection Block. This way you can define an aspect that does something on exception and weave it into all places in your code that need it.
If you just want to log the exceptions' messages and items, without doing special processing in the catch block, you could create a Reflection-based Object logger, passing the Exception as an argument. Doing so, you don't have a lot of catch blocks.
And if you are the code's owner, you can put the logging procedure inside the MySpecialException's constructor, removing the catch's block and making the code cleaner.
You could have something like:
public static class ErrorHandler
{
public static void HandleMyException(MyException myEx)
{
Debug.WriteLine(myEx.MyErrorString);
throw;
}
public static void HandleException(Exception myEx)
{
Debug.WriteLine(e.ToString());
throw;
}
}
or, in this specific case, have a more generic function like:
public static class ErrorHandler
{
public static void WriteAndThrow(string msg)
{
Debug.WriteLine(msg);
throw;
}
}