Handling multiple exceptions in a loop - c#

In my code, a method is being called repeatedly within a loop like so:
foreach (var file in files)
{
SomeMethod(file);
}
The method is likely to throw exceptions, but I don't want the code to exit the loop after the first exception.
Furthermore, the code above is being called from a web api controller, so I need a way to pass all the exception information back to the controller, where it will be handled (log exception and return error response to the client).
What I've done so far is catch and store all the exception in a list.
var errors = new List<Exception>();
foreach (var file in files)
{
try
{
SomeMethod(file);
}
catch(Exception ex)
{
errors.Add(ex);
}
}
Considering that rethrowing all the errors in the list is not an option, what is the best approach to return the exception information to the controller?

Use AggregateException.
You can pass the List<Exception> to its constructor and throw that.
At the end of your loop do:
AggregateException aggregateEx = new AggregateException(errors);
throw aggregateEx;
(or return AggregateException)

Based on Habib's suggestion, I've implemented a solution that also handles the case where there is just one exception. This way there are no unnecessarily nested exceptions.
if (errors.Any())
{
if (errors.Count > 1)
{
throw new AggregateException("Multiple errors. See InnerExceptions for more details",errors);
}
else
{
ExceptionDispatchInfo.Capture(errors[0]).Throw();
}
}
Simply rethrowing the single exception by calling throw errors[0]; should be avoided as it wouldn't preserve the stack trace of the original exception.

Related

Ignoring exceptions vs throwing it explicitly

Is it alright to return an empty object in case of an exception or should we throw the exception so that caller may know what has gone wrong?
public async Task<UserInfoModel> GetUserInfoByRole(Role role)
{
UserModel userInfo = new UserModel();
try
{
// do something
}
catch (Exception ex)
{
// do logging
// throw;
}
return userInfo;
}
It depends if you are creating a class, component, ... for others to use, you obviously should throw an exception. because they need to know about it and handle the exception the way that suits them.
If it is a method in your own code, may be returning a null value would be sufficient, because you might just check the return value and if it is null you know that there was an error and you don't want to program break because of the exception, otherwise you will need another exception handling again.

throw original exception inside Parallel methods instead of aggregate exception

I have two CPU-intensive methods inside a Parallel.Invoke call:
Parallel.Invoke(
() => { GetMaxRateDict(tradeOffObj); },
() => { GetMinRateDict(tradeOffObj); }
);
For a MCVE, assume:
public void GetMaxRateDict(object junk)
{
throw new Exception("Max exception raised, do foo...");
}
public void GetMinRateDict(object moreJunk)
{
throw new Exception("Min exception raised, do bar...")
}
I throw different exceptions in each of these inner methods. However, if one of these gets thrown, the Parallel wrapper throws a more generic exception: "One or more errors occurred", which is specific enough to show in my UI layer.
Can I grab the original exception somehow and throw it instead?
I would like the Parallel task to stop entirely if possible to raise the inner exception, but if that's not possible, at least being able to raise it once the two methods complete is what I need. Thanks.
Can I grab the original exception somehow and throw it instead?
"It" implies that there will only be on exception. Even though that's probably true, because you're executing actions in parallel you can't 100% rule out the possibility that multiple actions throw exceptions even if you attempt to cancel the others after the first exception. If you're okay with that, we can go from the assumption that we only expect one exception and we're okay with only catching one. (If you allow the other invocation to continue after one throws an exception the possibility of having two exceptions increases.)
You can use a cancellation token. If one of the invocations below throws an exception, it should catch that exception, place it in a variable or queue, and then call
source.Cancel;
Doing so will cause the entire Parallel.Invoke to throw an OperationCanceledException. You can catch that exception, retrieve the exception that was set, and rethrow that.
I'm going to go with the other answer's suggestion of a ConcurrentQueue just as a matter of practice because I don't think we can rule out the remote possibility that a second thread could throw an exception before being canceled.
This started off seeming small, but eventually it got so involved that I separated it into its own class. This makes me question whether my approach is needlessly complex. The main intent was to keep the messy cancellation logic from polluting your GetMaxRateDict and GetMinRateDict methods.
In addition to keeping your original methods unpolluted and testable, this class is itself testable.
I suppose I'll find out from the other responses whether this is a decent approach or there's something much simpler. I can't say I'm particularly excited about this solution. I just thought it was interesting and wanted to write something that did what you asked.
public class ParallelInvokesMultipleInvocationsAndThrowsOneException //names are hard
{
public void InvokeActions(params Action[] actions)
{
using (CancellationTokenSource source = new CancellationTokenSource())
{
// The invocations can put their exceptions here.
var exceptions = new ConcurrentQueue<Exception>();
var wrappedActions = actions
.Select(action => new Action(() =>
InvokeAndCancelOthersOnException(action, source, exceptions)))
.ToArray();
try
{
Parallel.Invoke(new ParallelOptions{CancellationToken = source.Token},
wrappedActions)
}
// if any of the invocations throw an exception,
// the parallel invocation will get canceled and
// throw an OperationCanceledException;
catch (OperationCanceledException ex)
{
Exception invocationException;
if (exceptions.TryDequeue(out invocationException))
{
//rethrow however you wish.
throw new Exception(ex.Message, invocationException);
}
// You shouldn't reach this point, but if you do, throw something else.
// In the unlikely but possible event that you get more
// than one exception, you'll lose all but one.
}
}
}
private void InvokeAndCancelOthersOnException(Action action,
CancellationTokenSource cancellationTokenSource,
ConcurrentQueue<Exception> exceptions)
{
// Try to invoke the action. If it throws an exception,
// capture the exception and then cancel the entire Parallel.Invoke.
try
{
action.Invoke();
}
catch (Exception ex)
{
exceptions.Enqueue(ex);
cancellationTokenSource.Cancel();
}
}
}
The usage would then be
var thingThatInvokes = new ParallelInvokesMultipleInvocationsAndThrowsOneException();
thingThatInvokes.InvokeActions(
()=> GetMaxRateDict(tradeOffObj),
() => GetMinRateDict(tradeOffObj));
If it throws an exception, it will be a single exception from one invocation failure, not an aggregate exception.
Not quite sure whether given example would answer your question, but it might improve overall solution:
private static void ProcessDataInParallel(byte[] data)
{
// use ConcurrentQueue to enable safe enqueueing from multiple threads.
var exceptions = new ConcurrentQueue<Exception>();
// execute the complete loop and capture all exceptions
Parallel.ForEach(data, d =>
{
try
{
// something that might fail goes here...
}
// accumulate stuff, be patient ;)
catch (Exception e) { exceptions.Enqueue(e); }
});
// check whether something failed?..
if (exceptions.Count > 0) // do whatever you like ;
}
Such an approach gives additional freedom in terms of collecting different kinds of exceptions into different queues (if necessary) or re-throwing aggregated exception further (such that no sensitive info bubbled up or you may convey particular exception with a user-friendly description of possible reasons, etc.).
Generally, that is correct way of exception management with parallelization. Not only in C#.

Exception handling - Exception within a catch clause?

I am downloading data from text files into db tables. The data in the files is occasionally corrupt at a field level (files are comma delimited .csv files)
I am reading each line into an object that represents the data line with properties that are the correct datatype.
If the read into the object fails due to dodgy data, I want to read the line into a similar object as the first one, only this one has all data types set to string so the read into it should not fal.
The idea being that I can create a collection of valid record objects which I will load in to the appropriate db table, and a collection of exceptions which I will load into an exceptions table. These can then be dealt with later.
So - the question:
I am going to loop through the lines of the text file and load these into the object and add the object to a collection. There will be a try/catch loop around this and if the object load fails, then in the catch section I will load the exception object and add this to the collection of exceptions.
However, what happens if the exception object load fails (for whatever reason). Do I put a try/catch around that and log exceptions - i.e a try/catch within a try/catch?
Is there a better way of doing this?
Code within a catch block is no way different to other code.
So you will have to protect every critical action with a try catch otherwise your program might crash.
2.
This might be a personal flavor, but I do not recommend to use try for control flow - do use if instead. So use if-statements to detect your dodgy data.
Yes. You can add the Try-Catch in other catch clause. It's OK.
Or as Imapler suggested, you can add the exception to a collection, and then process the collection in a loop. That's will let you process the lines with the exception later. But maybe it looks better than Try-Catch in a Catch clause.
var exceptionList = new List<ExceptionLines>();
try
{
// read lines, parse...
}
catch(Exception ex)
{
// handle the lines with the exception. Add the exception and the necessary arguments to the collection
exceptionList.Add( new ExceptionLines(....));
}
// do stuff
// handle the exceptions.
foreach(var exception in exceptionList)
{
try
{
// process the exception line.
}
catch(Exception ex)
{
// log error and handle exception
}
}
You can also wrap the exception with a wrapper. Maybe it will looks better.
// somewhere in your code...
WrapException( () =>
{
// read and parse lines...
}, (ex) =>
{
WrapException(ex, ParseToExceptionFunction, HandleExceptionParseFunction, false);
}, false);
void WrapException(Action func, Action<Exception> handleCatch, bool rethrow)
{
try
{
func();
}
catch(Exception ex)
{
handleCatch(ex);
if (rethrow)
throw;
}
}
static void WrapException<T>(T arg, Action<T> func, Action<Exception> handleCatch, bool rethrow)
{
try
{
func(arg);
}
catch (Exception ex)
{
handleCatch(ex);
if (rethrow)
throw;
}
}
void ParseToExceptionFunction(ArgType arg)
{
// try to parse to excetion
}
void HandleExceptionParseFunction(Exception ex)
{
// handle the exception for parsing the line with the exception
}
You can also implement the ParseToExceptionFunction and the HandleExceptionParseFunction as lambdas...
So I used everybody's advice.
Used if than else's to catch dodgy data, created a list of good data and a list of exceptions (raised by the if and else's) and then processed the lists in try / catches to catch any other exceptions that may arile (ref integrity issues etc)
Thanks for the advice.

How to not throw exception in ASP.NET Web Api service?

I am building a ASP.NET Web Api service and I would like to create centralized exception handling code.
I want to handle different types of exceptions in different ways. I will log all exceptions using log4net. For some types of exceptions I will want to notify an administrator via email. For some types of exceptions I want to rethrow a friendlier exception that will be returned to the caller. For some types of exceptions I want to just continue processing from the controller.
But how do I do that? I am using an Exception Filter Attribute. I have this code working. The attribute is registered properly and the code is firing. I just want to know how I can continue if certain types of exceptions are thrown. Hope that makes sense.
public class MyExceptionHandlingAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
//Log all errors
_log.Error(myException);
if(myException is [one of the types I need to notify about])
{
...send out notification email
}
if(myException is [one of the types that we continue processing])
{
...don't do anything, return back to the caller and continue
...Not sure how to do this. How do I basically not do anything here?
}
if(myException is [one of the types where we rethrow])
{
throw new HttpResponseException(new HttpResponseMessage(StatusCode.InternalServerError)
{
Content = new StringContent("Friendly message goes here."),
ReasonPhrase = "Critical Exception"
});
}
}
}
For some types of exceptions I want to just continue processing from the controller. But how do I do that?
By writing try..catch where you want this behaviour to occur. See Resuming execution of code after exception is thrown and caught.
To clarify, I assume you have something like this:
void ProcessEntries(entries)
{
foreach (var entry in entries)
{
ProcessEntry(entry);
}
}
void ProcessEntry(entry)
{
if (foo)
{
throw new EntryProcessingException();
}
}
And when EntryProcessingException is thrown, you actually don't care and want to continue execution.
If this assumption is correct: you can't do that with a global exception filter, as once an exception is caught, there's no returning execution to where it was thrown. There is no On Error Resume Next in C#, especially not when the exceptions are handled using filters as #Marjan explained.
So, remove EntryProcessingException from your filter, and catch that specific exception by changing the loop body:
void ProcessEntries(entries)
{
foreach (var entry in entries)
{
try
{
ProcessEntry(entry);
}
catch (EntryProcessingException ex)
{
// Log the exception
}
}
}
And your loop will happily spin to its end, but throw on all other exceptions where it will be handled by your filter.

Handling Casting exceptions in a foreach statement

Ok, lets say I have an array of objects in C# .Net like so:
object[] myObjects = new object[9];
myObjects[0] = "Foo";
myObjects[1] = 3;
myObjects[2] = 2.75;
myObjects[3] = "Bar";
myObjects[4] = 675;
myObjects[5] = "FooBar";
myObjects[6] = 12;
myObjects[7] = 11;
myObjects[8] = "FooBarFooBar";
I want to, inside a foreach block, enumerate this array and write every string to a text document using StreamWriter like so:
StreamWriter sw = new StreamWriter(#"C:\z\foobar.txt");
foreach(string myObject in myObjects)
{
sw.WriteLine(myObject);
}
sw.Flush();
sw.Close();
My problem is that whenever I try to cast the integers and doubles to String, an exception will be thrown.
If I put a try/catch block around my foreach statement, the exception that gets thrown on the second iteration will trigger the catching of the exception and nothing will get written to my text document.
Putting the try/catch inside the foreach is pointless because the exception happens on the cast.
I want to use a foreach loop (let's assume that for loops don't exist, and that we can't use indexing or ToString()) to enumerate an array of objects, casting each to a string and writing these to a text document using StreamWriter. If the cast works, happy days. If not, I want to catch the exception thrown and continue to enumerate the remaining objects.
Thanks
Edit: Before somebody says it, this isn't homework! I am trying to solve a real world problem.
Because you expect a heterogeneous collection, it's better to avoid throwing InvalidCastException in the first place. Read up on "boneheaded exceptions" in Eric Lippert's excellent Vexing exceptions article.
Option 1: Use the LINQ OfType<TResult>() extension method to pick out only elements of a specified type:
// using System.Linq;
foreach(string myObject in myObjects.OfType<string>())
{
sw.WriteLine(myObject);
}
Option 2: Do the type check yourself:
foreach(object myObject in myObjects)
{
string s = myObject as string;
if (s != null)
sw.WriteLine(s);
}
This option is easy to extend to handle multiple types.
UPDATE:
Ok, but what would happen if, in some outlandish scenario, an exception was still thrown on this line. Is there a way to handle the exception and then continue with my enumeration?
Here are the other ways an exception could be thrown on the foreach line, none of which you can sensibly handle:
myObjects.GetEnumerator() throws an exception. In this case, the enumeration can't be started at all.
IEnumerator<string>.MoveNext() throws an exception. In this case, the enumerator is likely to be corrupt, and enumeration cannot continue.
Some other type of fatal exception occurs: OutOfMemoryException, StackOverflowException, etc. In this case, you should just let the process die.
You don't need to cast the object to string yourself. StreamWriter has an overload that takes object and does the casting automatically (MSDN link):
foreach (object myObject in myObjects)
{
sw.WriteLine(myObject);
}
Can't you just catch and continue?
StreamWriter sw = new StreamWriter(#"C:\z\foobar.txt");
foreach(string myObject in myObjects)
{
try
{
sw.WriteLine(myObject);
}
catch (Exception ex)
{
// process exception here
continue;
}
}
sw.Flush();
sw.Close();
OK. I know that the question has been answered. But I thought this is interesting. If you want to really get hold of all the exceptions thrown within a foreach loop you could probably store it as a Generic List of type Exception and later you can throw it as an AggregateException
more info in this blog post and this MSDN link
Here is my implementation corresponding to your scenario (this will capture all exceptions thrown within the foreach loop and still the loop won't break until the object array is fully looped)
try
{
List<Exception> exceptions = null;
foreach (object myObject in myObjects)
{
try
{
string str = (string)myObject;
if (str != null)
{
sw.WriteLine(str);
}
}
catch (Exception ex)
{
if (exceptions == null)
exceptions = new List<Exception>();
exceptions.Add(ex);
}
}
if (exceptions != null)
throw new AggregateException(exceptions);
}
catch(AggregateException ae)
{
//Do whatever you want with the exception or throw it
throw ae;
}

Categories

Resources