When to handle the exception? - c#

I am writing an app that I can feed tasks with multiple steps. I have some code similar to what's below and I want to know if this is the normal way to handle exceptions. This code will probably never be seen by anyone else, but it could be, so I'd like to know I'm handling the exceptions as anyone would expect.
IEnumerable<Task> Tasks;
foreach(var task in Tasks)
{
try
{
//boiler plate prep for task (loading libraries, connecting, logging start, etc)
foreach(var step in task.Steps)
{
try
{
step.Execute();
}
catch(Exception ex)
{
LogStepError(step, ex);
throw;
}
}
//Notify parties task has been completed successfully, log task completion
}
catch(Exception ex)
{
LogTaskFailure(task);
}
finally
{
//close connections, etc
}
}
interface ITaskStep
{
void Execute()
{
}
}
I also wanted to add that the Task Steps are implementing the ITaskStep interface, so the implementation of Execute is not my own (well it is in this instance, but someone could implement the interface). My code just loads up the library and runs any ITasks and their ITaskSteps.

Go ahead and catch exceptions to log their existence. But if you haven't actually resolved the problem that led to the exception being thrown, then please rethrow it for the caller to handle. Don't swallow it up.
Your code above catches a TaskIsBogusException and a PrinterOnFireException and treats them the same way: Log it and keep going with the next task. Doing that with a bogus task is fine because you're done with the task anyway, but if you catch a PrinterOnFireException and don't rethrow it, then by golly, the printer had better not still be on fire.
If you're not going to rethrow, then only catch the specific exception types that your code knows how to handle at that point. Let everything else (either stuff you don't know how to handle, or stuff you never even thought of) propagate up to the next available exception handler.

You are catching ALL the exceptions which is OK and as you mentioned is the most common approach, but I don't think it is the right one.
I think you should catch specific exceptions. If you do that you could separate them and you will notice that there are some exceptions that you simply can't handled, but there are others that you can. The code will be better and more robust since you will exactly know what is happening on your code.
This is an example:
try
{
//Your stuff
}
catch(DivideByZeroException ex)
{
//Could you manage this?
}
catch(NullReferenceException ex)
{
//Could you manage this one?
}
catch(IOException ex)
{
//What about this one?
}
finally
{
//Any cleanup code
}

If step.Execute() is the only thing that's happening in your for loop, the following might be better: (edited in response to clarification)
IEnumerable<Task> Tasks;
foreach(var task in Tasks)
{
try
{
//boiler plate prep for task
}
catch(Exception ex)
{
LogTaskFailure(task);
continue;
}
foreach(var step in task.Steps)
{
try
{
step.Execute();
}
catch(Exception ex)
{
LogStepError(step, ex);
LogTaskFailure(task);
break;
}
}
}
class TaskStep
{
private void Execute()
{
//do some stuff, don't catch any exceptions
}
}
This way you don't rethrow the exception.

I have done something similar numbers of times when I have a list of tasks that I want to complete even if some of them fail. In fact there are times I know there is a good chance one might fail but I don't want to break out of the loop until all steps have completed.
I think it makes a lot of sense.

I think I might have written it like this, but you method works also.
foreach(var step in task.Steps)
{
try
{
step.Execute();
}
catch(Exception ex)
{
LogStepError(step, ex);
LogTaskFailure(task);
break;
}
}

You might want to handle the completion of your task using a return varibale and use Exception on the whole code pience to catch any generic exception.
Example:
try{
foreach(var step in task.Steps)
{
if(!step.Execute()){
break;
}
}
}catch(Exception ex)
{
}

Related

Handling Aggregate Exceptions in Service Fabric

Let's say I have a Web API service that calls my user Service to return user profile information etc..
UserProfileService can throw UserNotFoundException. When thrown, it is serialized and sent as an inner exception in an AggregateException which can be caught in the calling method. This service uses Service Fabric's service remoting for RPCing.
My WebAPI is calling my service like this:
[HttpGet]
public async Task<IActionResult> Get(int id)
{
try
{
var profile = await _userService.GetProfileAsync(int id);
return Json(profile);
} catch (AggregateException ae)
{
// Here I want to call NotFound() if `UserNotFoundException`
// was thrown, otherwise...
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
So a couple of questions here:
What do I do to handle expected exceptions?
Naively I'd do something like this:
try { /* ... */ } catch (AggregateException ae)
{
foreach(var e in ae.InnerExceptions)
{
if (e is UserNotFoundException)
{
return NotFound();
}
}
return errorResponse ?? StatusCode(StatusCodes.Status500InternalServerError);
}
But the trouble with this is, if there are multiple exceptions only one will "win". And, I believe - although there is no guarantee, that the earliest added Exceptions will have priority, as they'll have a lower index in InnerExceptions. Am I over thinking this, and would this solution be fine? The only time my custom exceptions will be thrown are when I know they should be thrown, surely?
This leads me to my other question:
Under what circumstances would you retrieve several exceptions in an AggregateException.
Is it when you have Task a calling Task b calling a Task c, c throws, b doesn't throw, a throws, you'd get aggregate exception containing a and c's exceptions?
I'll answer your questions backwards:
2) AggregateException has a contructor that allows an IEnumerable<Exception> as parameter. This is how it can contain multiple inner exceptions. This means that your aggregate exception won't contain more than one inner exception unless you explicitly throw an AggregateException with multiple inner exceptions. Say you have a Task a calling Task b calling Task c. If c throws an exception, which is not caught in a or b, a would throw an AggregateException with an inner AggregateException with an inner exception thrown by c.
1) Your example works just fine. If you want it a bit shorter you could catch it by inner exception:
try
{
// ...
}
catch (AggregateException ex) when (ex.InnerException is UserNotFoundException)
{
// ...
}
catch (AggregateException ex) when (ex.InnerException is SomeOtherException)
{
// ...
}
You could also catch them with some if-statements like you did in your example:
try
{
// ...
}
catch (AggregateException ex)
{
if (ex.InnerException is UserNotFoundException)
{
// ...
}
else if (ex.InnerException is SomeOtherExeption)
{
// ...
}
}
I would recommend to throw exceptions in all relevant classes, and to only catch those at the web service, that reports one error message to the web service caller. Keep the exception handling as simple as possible.
To rephrase: if something goes wrong in whatever code, just throw new Exception() with a string indicating what happened and where. The only place where you do try/catch is in the [httpget] Get().
If you really know what you are doing, you could implement serialized exceptions stuff, but then you would not ask about that here :-)

Unable to catch an Exception from Task.Run

I am following this MSDN guide to handle the exceptions within a Task.
This is what I wrote:
var myTask = Task.Run(() =>
{
throw new Exception("test");
});
try
{
myTask.Wait();
}
catch (Exception e)
{
return false;
}
I have set a breakpoint within the catch block, but at debug runtime, the code does not reach the breakpoint, and it's giving me:
Exception is unhandled by user code
I have no idea what is going on as I have followed very closely to the example from the MSDN guide. In fact, I copied the example to my project and it's still giving the same problem.
Is there any method I can handle the exception outside the Task? I need to return a boolean value based on the fact if the task throws any Exception or not.
Edit
To make it clearer for some of you, this is a more complete set of codes:
public bool ConnectToService()
{
try
{
// Codes for ServiceHost etc etc, which I'm skipping
// These codes are already commented out for this test, so they do nothing
var myTask = Task.Run(() =>
{
// Supposed to connect to a WCF service, but just throwing a test exception now to simulate what happens when the service is not running
throw new Exception("test");
});
try
{
myTask.Wait();
}
catch (Exception e)
{
return false;
}
return true;
}
catch (Exception)
{
return false;
}
}
Caller:
public void DoSomething()
{
try
{
// Other irrelevant stuff
if (ConnectToService())
{
DoAnotherThing();
}
}
catch (Exception)
{
}
}
I would also want to point out I have a solution for this, but it's puzzling why an example from MSDN isn't working for me. I would think that my own solution is not elegant, so I'm still looking for a more elegant solution.
Exception taskException = null;
var myTask = Task.Run(() =>
{
try
{
throw new Exception("test");
}
catch (Exception e)
{
taskException = e;
}
});
try
{
myTask.Wait();
if (taskException != null) throw taskException;
}
catch (Exception e)
{
return false;
}
When a task is run, any exceptions that it throws are retained and re-thrown when something waits for the task's result or for the task to complete
task.Wait() Rethrows any exceptions
task.Result Rethrows any exceptions
As well, your code works correctly
Just press f5 while catching an exception and you will see that will get your point
According to MSDN Task.Run:
Queues the specified work to run on the thread pool and returns a Task object that represents that work.
So You throwing your exception on different thread than you trying to catch it. You should deal with exception on same thread.
Alternatively you can deal with unhandled exceptions in global AppDomain.UnhandledException event.
Jai, as mentioned, this code will always work. I think you will have to enable some settings in visual studio. The setting is turned off and because of this, you are getting "Exception not handled by user code".
try checking Under Tools, Options, Debugging, General, Enable just my code.
Also, you can use something like below if you don't like to bother about try/catch stuff :
myTask.ContinueWith(<you can access Exception property here to see if there was an exception>)
I had the same Problem and solved with ContinueWith
See:
var task = Task.Run(() =>
{
ChatHubWrapper chatHub = Ordem_ServicoBLL.sendMensagemIniciarChatPelaVr(pessoaWrapper.OrdemServico);
foreach (var mensagem in chatHub.MensagensEnviadas)
ChatHub.sendMensagemTodaSala(pessoaWrapper.OrdemServico.ID, mensagem);
})
.ContinueWith((t) =>
{
if (t.IsFaulted)
setPanelErrorWhats(t.Exception.InnerException.Message); // or throw new Exception...
});
task.Wait();
if (task.IsCompleted)
Response.Redirect(pessoaWrapper.OrdemServico.getUrlViewOSSuporte());
With this you Don't need a create Exception taskException = null;
And is not good to use catch Inside Task.Run
#Jai, please try to move a Task.Run to the inside of try/catch block. I think Task.Run executes imediatelly so you may get exception because of that.

Problems with handling exceptions from async method with tasks

I hope you can help me with that problem.
I have a method that does specific actions, for example, I am sending a HttpWebRequest. There I can get a WebException, so I put it in a Try-Catch-block to rethrow exceptions for more specific exception messages.
Like that: (This is in a method called doWebRequest)
try
{
// HttpWebRequest here
}
catch (WebException ex)
{
throw new WebException(String.Format("My special additional message {0}", ex.Message);
}
Well, so this works, when I call this function normally.
But now I want an async way to do this. What I made to call this method in an async method:
public void DoRequestAsync()
{
Task internalRequest = new Task(doWebRequest);
internalRequest.ContinueWith(InternalUpdateSearchExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
internalRequest.Start();
}
So this makes a new task and then calls the method doWebRequest async.
To handle errors now, because I know it is different on async, I made this handler, which you can also see in internalRequest.ContinueWith. Looks like that:
private void InternalUpdateSearchExceptionHandler(Task task)
{
var ex = task.Exception;
if (ex.InnerException is WebException)
{
if ((ex.InnerException as WebException).Status == WebExceptionStatus.ProtocolError)
{
throw new WebException(ex.InnerException.Message);
}
else
{
throw new Exception("There was no response from the server.");
}
}
}
But this is not executing any exceptions. I don't know why.
At first I thought, this is because it cannot take the InnerException as a WebException, or would that work? If not, please tell me what to do here. But even when I throw an exception without any queries here, it did not throw any exceptions while debugging. Why is that?
Help is appreciated. When something is not clear, ask me. ;)
Your continuation is throwing an exception, but when that continuation throws an exception all that happens is the Task that represents that continuation is marked as Faulted with the given exception as its Exception. You currently are ignoring the task created by calling ContinueWith, so there is nothing to observe this exception.
DoRequestAsync likely shouldn't be void; rather it should return a Task, specifically the one created by calling ContinueWith, so that whoever calls this method can observe any exceptions thrown.
Also note that you could do this much more simply using async:
public async Task DoRequestAsync()
{
try
{
var content = await new WebClient()
.DownloadStringTaskAsync("address");
}
catch (WebException ex)
{
throw new WebException(String.Format("My special additional message {0}", ex.Message);
}
}

Proper exception handling when invoking WCF callback method

I have a series of WCF services that invoke methods on the client again (using WcfDuplexChannels) based on events at the server side. However, it seems there are quite some exceptions that can occur, so right now I have a huge try/catch block around every line calling back to the client, ending with disabling of the event in case any exception occurs. Besides being cumbersome to write every time, I'm not sure if I could simplify the try catch block by catching just a few base exceptions? Right now I don't really care what's causing the exceptions (I don't care whether it's faulted, aborted, disposed or timed out) but I do log the different exceptions.
I also read about IErrorHandler, but will that actually be suitable when invoking a method on the client?
Here's a sample of my current strategy:
private void OnProductChanged(List<DTO> products)
{
try
{
client.OnProductChanged(products);
return;
}
catch (TimeoutException)
{
log.Info("Communication to client timed out.");
}
catch (CommunicationObjectAbortedException)
{
log.Info("Connection to client is in aborted state.");
}
catch (CommunicationObjectFaultedException)
{
log.Info("Connection to client is in faulted state.");
}
catch (CommunicationException ce)
{
log.InfoFormat("CommunicationException occured on product change notification: {0}.", ce.Message);
}
catch (ObjectDisposedException)
{
log.Info("Communication channel is disposed.");
}
catch (Exception e)
{
log.WarnFormat("Unhandled {0} on client callback: {1}", e.GetType(), e.Message);
}
SendProductChanged = false;
}
The SendProductChanged = false; line will take care of unbinding the event handler.
You can write a wrapper method which takes Actions of Funcs as parameters and you can use try catch blocks inside this function. You can call your functions using this function; something like:
public void CallMethod(Action methodToBeCalled)
{
try
{
methodToBeCalled();
}
catch
.....
....
}
Then call your functions like:
CallMethod(() => client.OnProductChanged(products));

How to catch errors from worker threads in console application written in C#

I currently have a small console application that runs a number of Tasks (using Parallel.ForEach) and each one of these tasks creates sub-threads using ThreadPool.QueueUserWorkItem.
I would like the application to handle any exception thrown by these tasks/threads.
Will surrounding the Parallel.ForEach statement with try..catch work if the threads throw any errors or will they just die out?
EDIT: These sub-threads simulate users of the system. Refer to this question.
Surrounding the statement will not do the job. You can do something like this:
public static void Main(string[] args)
{
string[] files = System.IO.Directory.GetFiles(#".", "*.*");
Parallel.ForEach(files, x =>
{
try
{
MyAction(x);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
}
static void MyAction(string x)
{
throw new ApplicationException("Testing: " + x);
}
Don't use QUWI. I have a brief comparison of background task types on my blog (Task, BackgroundWorker, Delegate.BeginInvoke, ThreadPool.QueueUserWorkItem, and Thread).
For background tasks, Task is the clear winner. QueueUserWorkItem is very low-level by comparison.
In particular, your problem is error propogation, and Task has built-in support for this that is entirely lacking in QueueUserWorkItem. You could build it in yourself by wrapping your delegate in a try/catch, storing the exception as part of the delegate argument (or as a bound variable of a lambda expression), explicitly checking it later, and doing some technically unsupported reflection to preserve the stack trace.
But why bother? Task supports error propogation out of the box.
you can handle all exceptions with try/catch, for example:
try
{
MyParallelMethod();
}
catch(Exception e)
{
//...
}
and in your method, do something like that:
public void MyParallelMethod()
{
var data = new List<String>();
//...
Parallel.ForEach(data, d =>
{
try
{
//...
}
catch (Exception e)
{
//...
}
});
}
Will surrounding the Parallel.ForEach statement with try..catch work if the threads throw any errors or will they just die out?
No, you need to put try/catch inside the sub threads.
Error handling must be implemented in the task itself (the job each ). You need to make sure the task you are creating handles the exception.
Parallel.ForEach will not handle it for you since the exception will be raised not in the thread which is calling the Parallel.ForEach.
Alternative is to use Task<T>.

Categories