I have a repository that will throw an EntityNotFoundException when its GetSingle<T>(int id) method cannot find the requested entity in the database. When I use this with AutoMapper and an exception occurs, I get something like this instead:
AutoMapperMappingException: Trying to map CategoryDTO to Category... --->
AutoMapperMappingException: Trying to map System.Int32 to CategoryType... --->
AutoMapper.MappingException: Trying to map System.Int32 to CategoryType... --->
EntityNotFoundException: entity of type CategoryType with ID 5 was not found in the database
My custom exception is 4 levels down. This makes it hard to use try-catch blocks because now I have to do something like this:
try
{
// do the mapping
}
catch (AutoMapperMappingException e)
{
// get the inner-most exception
while (e.InnerException != null)
{
e = e.InnerException;
}
// check to see if it's an EntityNotFoundException
if (e.GetType() == typeof (EntityNotFoundException))
{
var notFound = e as EntityNotFoundException;
// do something specific here, like inform the user
}
else
{
// do something more generic
}
What I'd like to be able to do is just this:
try
{
// do the mapping
}
catch (EntityNotFoundException e)
{
// do something specific here, like inform the user
}
catch (Exception e)
{
// do something more generic
}
Is there any way of disabling AutoMapper's exception wrapping behavior so that I get the straight-up exceptions that are being thrown?
Answer
I ended up creating a thin wrapper around AutoMapper that will catch the AutoMapperMappingException, find the inner-most exception, and throw that:
public class AutoMapperWrapper
{
public TB Map<TA, TB>(TA source, TB destination)
{
// try to do the mapping
try
{
return Mapper.Map(source, destination);
}
// catch AutoMapper's exception
catch (Exception e)
{
// find the first InnerException that's not wrapped
while (e is AutoMapperMappingException)
{
e = e.InnerException;
}
// if the inner exception is null, throw the original exception
if (e == null)
{
throw;
}
// otherwise, throw the inner exception
else
{
throw e;
}
}
}
}
The downside of this method though is that sometimes the entire exception tree is useful to look at to see which property or entity mapping AutoMapper failed on, but this code will only give you the inner-most exception, which is sometimes not very helpful by itself, like InvalidCastException: "could not convert string to int", but won't tell you which property it was.
I thing it would be bad design to conditionally wrap exception so I guess the only thing to do is to drill down into inner exception and find the first none automapperexception.
I've implemented AutoMapperMappingException unwrapping in my NArms.AutoMapper library (see issue). It main purpose is to reduce code amount by providing MapTo<>() extension method which can be used instead of Mapper.Map(). You can get it via NuGet.
Obviously, source code is available at GitHub.
Related
I'm trying to catch specific SqlException 515 (Cannot insert the value NULL into column), and I cannot precheck the value before the actual INSERT. I can only capture the error and determine what error it was.
In the following execution, the alert() can display of these msgs: that there's an empty value somewhere (from SqlException 515) or the generic error saying that something's wrong.
In this case, I know I can create and throw a custom exception error, but I would like to use only what I have here available since the SqlException will capture the exact error.
Also, those two methods are in two different classes and I only want to include System.Data.SqlClient where the Insert() method is.
Finally, I can use the regular System.Exception with substring method and search for a particular string. But there should be a better way.
So here's my pseudocode:
public void InsertNewCar()
{
try
{
Car myCar = new Car();
myCar.Insert();
}
catch (Exception ex)
{
alert(msg); //Alerts the user: "Something missing" or "generic error"
}
}
public void Insert()
{
try
{
SqlHelper.ExecuteNonQuery(ConnString, CommandType.Text, sqlInsert);
}
catch (SqlException ex)
{
if (ex.Number == 515)
{
//throw exception specifying that something's missing in the INSERT
}
else
{
throw ex; //throw ex that will be interpreted as a generic error.
}
}
}
My question is: once I capture SqlException 515, what can I do with it? Once I throw it, I cannot check for error number within InsertNewCar().
I can have Insert() return a value, but then the Exception will not be thrown. And I don't want to use ref keyword.
Thanks.
You could rethrow it with a specific, other exception:
throw new SomethingMissingException("Some guiding text", ex /*the original exception*/);
In that way, you can handle it somewhere else in a more generic way. Also, don't forget to add the original exception to the exception you throw. It may come in handy some time.
i'm calling a function that throws a custom exception:
GetLockOwnerInfo(...)
This function in turn is calling a function that throws an exception:
GetLockOwnerInfo(...)
ExecuteReader(...)
This function in turn is calling a function that throws an exception:
GetLockOwnerInfo(...)
ExecuteReader(...)
ExecuteReader(...)
And so on:
GetLockOwnerInfo(...)
ExecuteReader(...)
ExecuteReader(...)
ExecuteReaderClient(...)
Fill(...)
One of these functions throws an SqlException, although that code has no idea what an SqlException is.
Higher levels wrap that SqlException into another BusinessRuleException in order to include some special properties and additional details, while including the "original" exception as InnerException:
catch (DbException ex)
{
BusinessRuleExcpetion e = new BusinessRuleException(ex)
...
throw e;
}
Higher levels wrap that BusinessRuleException into another LockerException in order to include some special properties and additional details, while including the "original" exception as InnerException:
catch (BusinessRuleException ex)
{
LockerException e = new LockerException(ex)
...
throw e;
}
The problem now is that i want to catch the origianl SqlException, to check for a particular error code.
But there's no way to "catch the inner exception":
try
{
DoSomething();
}
catch (SqlException e)
{
if (e.Number = 247)
{
return "Someone";
}
else
throw;
}
i thought about catching SqlException right when it's thrown, and copy various values to the re-thrown exception - but that code is not dependant on Sql. It is experiencing an SqlException, but it has no dependency on SqlException.
i thought about catching all exceptions:
try
{
DoSomething(...);
}
catch (Exception e)
{
SqlException ex = HuntAroundForAnSqlException(e);
if (ex != null)
{
if (e.Number = 247)
{
return "Someone";
}
else
throw;
}
else
throw;
}
But that's horrible code.
Given that .NET does not let you alter the Message of an Exception to include additional information, what is the intended mechanism to catch original exceptions?
You need c# 6 / visual studio 2015 in order to do this using a predicate:
catch (ArgumentException e) when (e.ParamName == “…”)
{
}
Official C# Try/Catch Documentation
I hate to have to tell you this, but you cannot catch an inner exception.
What you can do is inspect one.
I suggest you catch your high-level exception (I believe it was LockerException) and inspect the InnerException property of that exception. Check the type, and if it's not a SqlException, check the InnerException of that exception. Walk each one until you find a SqlException type, then get the data you need.
That said, I agree with dasblinkenlight that you should consider -- if possible -- a heavy refactor of your exception framework.
Checking the error code of a wrapped exception is not a good practice, because it hurts encapsulation rather severely. Imagine at some point rewriting the logic to read from a non-SQL source, say, a web service. It would throw something other than SQLException under the same condition, and your outer code would have no way to detect it.
You should add code to the block catching SQLException to check for e.Number = 247 right then and there, and throw BusinessRuleException with some property that differentiates it from BusinessRuleException thrown in response to non-SQLException and SQLException with e.Number != 247 in some meaningful way. For example, if the magic number 247 means you've encountered a duplicate (a pure speculation on my part at this point), you could do something like this:
catch (SQLException e) {
var toThrow = new BusinessRuleException(e);
if (e.Number == 247) {
toThrow.DuplicateDetected = true;
}
throw toThrow;
}
When you catch BusinessRuleException later, you can check its DuplicateDetected property, and act accordingly.
EDIT 1 (in response to the comment that the DB-reading code cannot check for SQLException)
You can also change your BusinessRuleException to check for SQLException in its constructor, like this:
public BusinessRuleException(Exception inner)
: base(inner) {
SetDuplicateDetectedFlag(inner);
}
public BusinessRuleException(string message, Exception inner)
: base(message, inner) {
SetDuplicateDetectedFlag(inner);
}
private void SetDuplicateDetectedFlag(Exception inner) {
var innerSql = inner as SqlException;
DuplicateDetected = innerSql != null && innerSql.Number == 247;
}
This is less desirable, because it breaks encapsulation, but at least it does it in a single place. If you need to examine other types of exceptions (e.g. because you've added a web service source), you could add it to the SetDuplicateDetectedFlag method, and everything would work again.
Having an outer application layer care about the details of a wrapped exception is a code smell; the deeper the wrapping, the bigger the smell. The class which you now have wrapping the SqlException into a dbException is presumably designed to expose an SqlClient as a generic database interface. As such, that class should include a means of distinguishing different exceptional conditions. It may, for example, define a dbTimeoutWaitingForLockException and decide to throw it when it catches an SqlException and determines based upon its error code that there was a lock timeout. In vb.net, it might be cleaner to have a dbException type which exposes an ErrorCause enumeration, so one could then say Catch Ex as dbException When ex.Cause = dbErrorCauses.LockTimeout, but unfortunately exception filters are not usable in C#.
If one has a situation where the inner-class wrapper won't know enough about what it's doing to know how it should map exceptions, it may be helpful to have the inner-class method accept an exception-wrapping delegate which would take an exception the inner class has caught or would "like" to throw, and wrap it in a way appropriate to the outer class. Such an approach would likely be overkill in cases where the inner class is called directly from the outer class, but can be useful if there are intermediate classes involved.
Good question and good answers!
I just want to supplement the answers already given with some further thoughts:
On one hand I agree with dasblinkenlight and the other users. If you catch one exception to rethrow an exception of a different type with the original exception set as the inner exception then you should do this for no other reason than to maintain the method's contract. (Accessing the SQL server is an implementation detail that the caller is not/must not/cannot be aware of, so it cannot anticipate that a SqlException (or DbException for that matter) will be thrown.)
Applying this technique however has some implications that one should be aware of:
You are concealing the root cause of the error. In your example you are reporting to the caller that a business rule was invalid(?), violated(?) etc., when in fact there was a problem accessing the DB (which would be immediately clear if the DbException were allowed to bubble up the call stack further).
You are concealing the location where the error originally occurred. The StackTrace property of the caught exception will point to a catch-block far away from the location the error originally occurred. This can make debugging notoriously difficult unless you take
great care to log the stack traces of all the inner exceptions as well. (This is especially true once the software has been deployed into production and you have no means to attach a
debugger...)
Given that .NET does not let you alter the Message of an Exception to include additional information, what is the intended mechanism to catch original exceptions?
It is true that .NET does not allow you to alter the Message of an Exception. It provides another mechanism however to supply additional information to an Exception via the Exception.Data dictionary. So if all you want to do is add additional data to an exception, then there is no reason to wrap the original exception and throw a new one. Instead just do:
public void DoStuff(String filename)
{
try {
// Some file I/O here...
}
catch (IOException ex) {
// Add filename to the IOException
ex.Data.Add("Filename", filename);
// Send the exception along its way
throw;
}
}
As other peeps say, you cannot catch an the InnerException. A function such as this could help you get the InnerException out of the tree though:
public static bool TryFindInnerException<T>(Exception top, out T foundException) where T : Exception
{
if (top == null)
{
foundException = null;
return false;
}
Console.WriteLine(top.GetType());
if (typeof(T) == top.GetType())
{
foundException = (T)top;
return true;
}
return TryFindInnerException<T>(top.InnerException, out foundException);
}
I agree with the other comments that this is a code smell 🦨 and should be avoided. But if a refactor is not possible you could try something like this...
Create an extension method...
public static bool HasInnerException(this Exception ex, Func<Exception, bool> match)
{
if (ex.InnerException == null)
{
return false;
}
return match(ex.InnerException) || HasInnerException(ex.InnerException, match);
}
And use it like...
catch (Exception ex) when (ex.HasInnerException(e => e is MyExceptionThatIsHidden))
{
...
But really you should be solving for 👇
var exception = new Exception("wrapped exception 3",
new Exception("wrapped exception 2",
new Exception("wrapped exception 1",
new MyExceptionThatIsHidden("original exception")))); // <--- ???
I want to make a method, that throws a specific exception, by a parameter I give to the method. I have 3 userdefined exceptions, so instead of having to throw them every time I want to use them I want to make a method that handels it, so the parameter I give with my method is the exception I want to throw, but how do I do that?
I want to do something like this, but I am not really sure how to do it.
private void ExceptionMethod(custom exception)
{
try
{
//code that might fail
}
catch(exception ex)
{
throw new exception given by parameter(parameters from the exception);
}
}
FWIW I don't think this is a particulary good idea. Really, just throw your exception where it occurs, future maintainers of the code will thank you. (or at least not curse you)
If you have to do this thing, then its probably a better idea to pass an enumeration that you can switch on rather than the exception itself, then simply write a case statement to throw the exception you want.
Apart from the fact that this sounds like a bad idea, you can try the following:
private void TryElseThrow<TCustomException>(Action codeThatMightFail)
where TCustomException : Exception
{
try
{
codeThatMightFail();
}
catch (Exception e)
{
// Since there isn't a generic type constraint for a constructor
// that expects a specific parameter, we'll have to risk it :-)
throw
(TCustomException)Activator
.CreateInstance(typeof(TCustomException), e);
}
}
Use like so:
TryElseThrow<MyCustomException>(
() =>
{
throw new InvalidOperationException();
}
);
You were actually quite close:
private void ExceptionMethod(Exception customException)
{
try
{
//code that might fail
}
catch(Exception ex)
{
throw customException;
}
}
Will work, though I wouldn't recommend it for two reasons:
Catching Exception is a bad idea - you should just catch the exceptions that your code raises.
It's not a very good design (as others have pointed out).
So i dont see any problem in that.. as you say you already have your Custom Exception Written then you can do it like this.
in your parameter:
private void ExceptionMethod(CustomException myexception)
in catch:
throw myexception;
though its not a good Coding Design
Wouldn't it just be:
private void ExceptionMethod(MyCustomException exception)
{
try
{
//code that might fail
}
catch
{
throw exception;
}
}
When C# throws an exception, it can have an inner exception. What I want to do is get the inner-most exception, or in other words, the leaf exception that doesn't have an inner exception. I can do this in a while loop:
while (e.InnerException != null)
{
e = e.InnerException;
}
But I was wondering if there was some one-liner I could use to do this instead.
Oneliner :)
while (e.InnerException != null) e = e.InnerException;
Obviously, you can't make it any simpler.
As said in this answer by Glenn McElhoe, it's the only reliable way.
I believe Exception.GetBaseException() does the same thing as these solutions.
Caveat: From various comments we've figured out it doesn't always literally do the same thing, and in some cases the recursive/iterating solution will get you further. It is usually the innermost exception, which is disappointingly inconsistent, thanks to certain types of Exceptions that override the default. However if you catch specific types of exceptions and make reasonably sure they're not oddballs (like AggregateException) then I would expect it gets the legitimate innermost/earliest exception.
Looping through InnerExceptions is the only reliable way.
If the caught exception is an AggregateException, then GetBaseException() returns only the innermost AggregateException.
http://msdn.microsoft.com/en-us/library/system.aggregateexception.getbaseexception.aspx
If you don't know how deep the inner exceptions are nested, there is no way around a loop or recursion.
Of course, you can define an extension method that abstracts this away:
public static class ExceptionExtensions
{
public static Exception GetInnermostException(this Exception e)
{
if (e == null)
{
throw new ArgumentNullException("e");
}
while (e.InnerException != null)
{
e = e.InnerException;
}
return e;
}
}
I know this is an old post, but I'm surprised nobody suggested GetBaseException() which is a method on the Exception class:
catch (Exception x)
{
var baseException = x.GetBaseException();
}
This has been around since .NET 1.1. Documentation here:
http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs.71).aspx
Sometimes you might have many inner exceptions (many bubbled exceptions).
In which case you might want to do:
List<Exception> es = new List<Exception>();
while(e.InnerException != null)
{
es.add(e.InnerException);
e = e.InnerException
}
You could use recursion to create a method in a utility class somewhere.
public Exception GetFirstException(Exception ex)
{
if(ex.InnerException == null) { return ex; } // end case
else { return GetFirstException(ex.InnerException); } // recurse
}
Use:
try
{
// some code here
}
catch (Exception ex)
{
Exception baseException = GetFirstException(ex);
}
The extension method suggested (good idea #dtb)
public static Exception GetFirstException(this Exception ex)
{
if(ex.InnerException == null) { return ex; } // end case
else { return GetFirstException(ex.InnerException); } // recurse
}
Use:
try
{
// some code here
}
catch (Exception ex)
{
Exception baseException = ex.GetFirstException();
}
Not quite one line but close:
Func<Exception, Exception> last = null;
last = e => e.InnerException == null ? e : last(e.InnerException);
In fact is so simple, you could use Exception.GetBaseException()
Try
//Your code
Catch ex As Exception
MessageBox.Show(ex.GetBaseException().Message, My.Settings.MsgBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
End Try
You have to loop, and having to loop, it's cleaner to move the loop into a separate function.
I created an extension method to deal with this. It returns a list of all of the inner exceptions of the specified type, chasing down Exception.InnerException and AggregateException.InnerExceptions.
In my particular problem, chasing down the inner exceptions was more complicated than usual, because the exceptions were being thrown by the constructors of classes that were being invoked through reflection. The exception we were catching had an InnerException of type TargetInvocationException, and the exceptions we actually needed to look at were buried deep in the tree.
public static class ExceptionExtensions
{
public static IEnumerable<T> innerExceptions<T>(this Exception ex)
where T : Exception
{
var rVal = new List<T>();
Action<Exception> lambda = null;
lambda = (x) =>
{
var xt = x as T;
if (xt != null)
rVal.Add(xt);
if (x.InnerException != null)
lambda(x.InnerException);
var ax = x as AggregateException;
if (ax != null)
{
foreach (var aix in ax.InnerExceptions)
lambda(aix);
}
};
lambda(ex);
return rVal;
}
}
Usage is pretty simple. If, for example, you want to know if we encountered a
catch (Exception ex)
{
var myExes = ex.innerExceptions<MyException>();
if (myExes.Any(x => x.Message.StartsWith("Encountered my specific error")))
{
// ...
}
}
I ran into this and wanted to be able to list all of the exception messages from the exception "stack". So, I came up with this.
public static string GetExceptionMessages(Exception ex)
{
if (ex.InnerException is null)
return ex.Message;
else return $"{ex.Message}\n{GetExceptionMessages(ex.InnerException)}";
}
Another way you could do it is by calling GetBaseException() twice:
Exception innermostException = e.GetBaseException().GetBaseException();
This works because if it is an AggregateException, the first call gets you to the innermost non-AggregateException then the second call gets you to the innermost exception of that exception. If the first exception is not an AggregateException, then the second call just returns the same exception.
I have the following try-catch statement and I do not want to not throw the exception if the message property contains 'My error' in the text.
How can I programmatcially accomplish this? Also, would this be considered code-smell?
try
{
}
catch(Exception e)
{
if(e.Messages.Contains("My error"))
{
//want to display a friendly message and suppress the exception
}
else
{
throw e;
}
}
You shouldn't catch errors based on the error test. You should make your own exception class that extends exception:
class MyErrorException : Exception { }
and throw and catch those. (Excuse my syntax if it's wrong, I haven't done C# in a while).
That being said, throwing and catching your own Exceptions instead of propagating them is perfectly normal, and it is how you actually should do exception handling.
You should be catching the specific exception you're looking for. Quite frankly, that code is shocking. You should have something like ...
public class MyCoolException : Exception {
public MyCoolException(string msg) : base(msg) {}
}
public void MyCoolMethod() {
// if bad things happen
throw new MyCoolException("You did something wrong!");
}
Then later in your code you can use it like ...
try {
MyCoolMethod();
} catch (MyCoolException e) {
// do some stuff
}
Your code creates maintainability issues because a simple text change can have strange side effects. You can have your own exception class which inherits from System.Exception. Then instead of having an if you could do the following:
try
{
}
catch(MyException myException) //or just catch(MyException)
{
//display a friendly message
}
also you don't want to do throw e because it doesn't preserver the Stack, just throw; will do.
When I throw Exception rather than a derived class I always mean a failed assertion. I don't like failing out the backend because we are still able to receive a request (just not that one again). If we're really toast it will just error out on the next request anyway.
When the back end needs to generate an error message I have a ErrorMessage class that inherits from Exception and takes ErrorMessage and ErrorMessageTitle as constructor arguments.