After an exception, keep on running - c#

For example:
try
{
Task1();
Task2();
Task3();
}
catch (Exception ex)
{
}
Right now if an exception occurs in Task1(), the code in Task2 and Task2 method does not run. The program stops.
How could I make it so when an exception occurs, the code / methods that below it would keep on running to the end.
Thanks

An exception moves execution to the end of the try block and into the catch block. To do what you want, you'd have to use separate try/catch blocks:
try
{
Task1();
}
catch (Exception ex)
{
}
try
{
Task2();
}
catch (Exception ex)
{
}
try
{
Task3();
}
catch (Exception ex)
{
}
You could put your tasks in a collection (provided they all have the same signature) and loop, but the net effect would be the same:
var tasks = new Action[] {Task1, Task2, Task3};
foreach(var task in tasks)
{
try
{
task();
}
catch (Exception ex)
{
}
}

Currently, in the code that you have, if there is an exception throw trying to start Task1() then the other two tasks are not started. If that task is started without error but results in a task that is in a Faulted state, then your other tasks are properly started.
Generally one would not expect methods like these to throw an exception starting the task in most situations. Null checking arguments is something commonly done, but other than that one would generally expect such methods to not fail to start the task. If you have any control over the method, consider re-designing it so that it generates a faulted task instead of throwing an exception, unless you have a good reason to do otherwise.
You may also want to create a method that takes a task-returning method and, if it fails to generate a task, instead creates a faulted task. If it is successful, it can just return that task:
public static Task WrapExceptions(this Func<Task> function)
{
try
{
return function();
}
catch (Exception e)
{
var tcs = new TaskCompletionSource<bool>();
tcs.SetException(e);
return tcs.Task;
}
}
If you want to ensure all tasks are started even if there is an exception when starting the task, then you need to wrap each method call in its own try/catch.

Put each statement in its own try-catch block:
try
{
Task1();
}
catch (Exception ex)
{
}
try {
Task2();
}
catch (Exception ex)
{
}
try {
Task3();
}
catch (Exception ex)
{
}

Related

Handling multiple exceptions from async parallel tasks

Problem
Several tasks are run in parallel, and all, none, or any of them might throw exceptions. When all the tasks have finalized, all the exceptions that might have happened must be reported (via log, email, console output.... whatever).
Expected behavior
I can build all the tasks via linq with async lambdas, and then await for them running in parallel with Task.WhenAll(tasks). Then I can catch an AggregateException and report each of the individual inner exceptions.
Actual behavior
An AggregateException is thrown, but it contains just one inner exception, whatever number of individual exceptions have been thrown.
Minimal complete verifiable example
static void Main(string[] args)
{
try
{
ThrowSeveralExceptionsAsync(5).Wait();
}
catch (AggregateException ex)
{
ex.Handle(innerEx =>
{
Console.WriteLine($"\"{innerEx.Message}\" was thrown");
return true;
});
}
Console.ReadLine();
}
private static async Task ThrowSeveralExceptionsAsync(int nExceptions)
{
var tasks = Enumerable.Range(0, nExceptions)
.Select(async n =>
{
await ThrowAsync(new Exception($"Exception #{n}"));
});
await Task.WhenAll(tasks);
}
private static async Task ThrowAsync(Exception ex)
{
await Task.Run(() => {
Console.WriteLine($"I am going to throw \"{ex.Message}\"");
throw ex;
});
}
Output
Note that the output order of the "I am going to throw" messages might change, due to race conditions.
I am going to throw "Exception #0"
I am going to throw "Exception #1"
I am going to throw "Exception #2"
I am going to throw "Exception #3"
I am going to throw "Exception #4"
"Exception #0" was thrown
That's because await "unwraps" aggregate exceptions and always throws just first exception (as described in documentation of await), even when you await Task.WhenAll which obviously can result in multiple errors. You can access aggregate exception for example like this:
var whenAll = Task.WhenAll(tasks);
try {
await whenAll;
}
catch {
// this is `AggregateException`
throw whenAll.Exception;
}
Or you can just loop over tasks and check status and exception of each.
Note that after that fix you need to do one more thing:
try {
ThrowSeveralExceptionsAsync(5).Wait();
}
catch (AggregateException ex) {
// flatten, unwrapping all inner aggregate exceptions
ex.Flatten().Handle(innerEx => {
Console.WriteLine($"\"{innerEx.Message}\" was thrown");
return true;
});
}
Because task returned by ThrowSeveralExceptionsAsync contains AggregateException we thrown, wrapped inside another AggregateException.

Why is a finally block *sometimes* not executed on ThreadAbortException if it contains an await?

UPDATE: I don't think this question is a duplicate of Can ThreadAbortException skip finally? because (1) I'm not creating another thread, so there's no possibility of a race condition, and (2) this behavior only occurs if the finally block contains an await, which that other question doesn't mention.
Consider this console program:
class Program
{
static void Main()
{
try { T().GetAwaiter().GetResult(); }
catch (ThreadAbortException) { Thread.ResetAbort(); }
catch { }
}
static async Task Abort()
{
//await Task.Delay(1); // A
Thread.CurrentThread.Abort(); // B
}
static async Task T()
{
try
{
await Abort();
}
catch
{
Console.WriteLine("catch");
throw;
}
finally
{
Console.WriteLine("finally");
await Task.Yield(); // C
}
}
}
When I compile this in Visual Studio 2015, the output is
catch
But if I make any one of these changes...
Uncomment line A (and delete the call to Thread.ResetAbort() in Main—another oddity)
Change line B to throw new Exception();
Delete line C
then the output is
catch
finally
Is this behavior a bug, or is it by design (and documented somewhere)?
NOTE: In my actual scenario (an ASP.NET app), the ThreadAbortException is thrown by HttpResponse.Redirect, and I'm performing async I/O in the finally block.

Task swallows the exception thrown

In the method below, when an exception is thrown in the TRY block, it is being swallowed. How can I make it throw the exception so that it gets written to log in the catch block? The log writer works fine. Thanks!
public static bool MonitorQueueEmptyTask(string queueName, CancellationTokenSource tokenSource)
{
try
{
Task<bool> task = Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!"); //THIS THROW IS SWALLOWED -- NO LOG WRITTEN ON CATCH
};
return true;
}, tokenSource.Token);
}
catch (Exception ex)
{
WriteExceptionToLog(ex.Stack); //it's not that this method doesn't work. it works fine.
return false;
}
return true;
}
If you want to fire and forget, you can attach a continuation using ContinueWith. The current try-catch will not help you at all, as the exception is encapsulated inside the Task. If this is "fire and forget", than you can log the exception:
public static Task MonitorQueueEmptyTask(
string queueName, CancellationTokenSource tokenSource)
{
return Task.Factory.StartNew<bool>(() =>
{
while (!QueueManager.IsQueueEmpty(queueName))
{
if (tokenSource.IsCancellationRequested)
{
break;
}
Thread.Sleep(5000);
throw new Exception("Throwing an error!");
};
}, tokenSource.Token, TaskCreationOptions.LongRunning).ContinueWith(faultedTask =>
{
WriteExceptionToLog(faultedTask.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
This, in turn, will not propagate the exception after it's thrown, but will provide a mechanism to log the error. If you want the exception to be properly handled, you can register to TaskScheduler.UnobservedTaskException. Additionally, you can set ThrowUnobservedTaskExceptions enabled="true" in your configuration if you want unhandled exceptions to terminate your application. ContinueWith will consider the exception "handled" once you look at the task.Exception property.
The exception is not swallowed; it's just that it doesn't occur on the thread that executes the try/catch block, but on the separate Task thread.
If you don't observe the task's result or exception, when the task is eventually garbage collected, it will throw an exception saying that the task was not observed. Unless you catch that by handling the TaskScheduler.UnobservedTaskException, it will crash the process.
I also had a problem with this, and i really dislike the whole idea of App.config, so can provide another solution to prevent the exceptions disappearing :)
Save the exception then throw it after the Task.Run has completed, e.g.
private async void Function() {
Exception save_exception = null;
await Task.Run(() => {
try {
// Do Stuff
} catch (Exception ex) {
save_exception = ex;
}
}).ContinueWith(new Action<Task>(task => {
if (save_exception != null)
throw save_exception;
// Do Stuff
}));
}

Task Factory Method with Delay

I'm trying to call a particular method with 5 mins delay:
try
{
HttpContext ctx = HttpContext.Current;
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
HttpContext.Current = ctx;
System.Threading.Thread.Sleep(5 * 60 * 1000);
Sendafter5mins(param1,params2);
});
}
catch (Exception EX)
{
//Log Exception if any
}
This method is failing silently sometimes without any exception in log.
Please Suggest me is this the right way to fire a method with 5 mins delay.
Since you don't await the Task, nor Wait() on it, any exception thrown from Sendafter5mins(..) will not get caught in your catch block. If you are not using .NET 4.5, this should fail the whole process since the exception will fail the finalizer thread. Change your code to:
try
{
HttpContext ctx = HttpContext.Current;
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
try
{
HttpContext.Current = ctx;
System.Threading.Thread.Sleep(5 * 60 * 1000);
Sendafter5mins(param1,params2);
}
catch(Exception e)
{
//Log Exception if any
}
});
}
catch (Exception EX)
{
//This will catch unlikely exceptions thrown from HttpContext ctx = HttpContext.Current
// or the creation of the Task
}
If by "failing silently" you mean there's an exception and you don't catch it that's because you are starting a new task without waiting for the result. Your try-catch can't catch the exception as it's stored inside the task and isn't rethrown.
Anyways, if all you want is a delay use Task.Delay with async-await instead of creating a new Task and blocking its thread:
async Task SendAfterDelay()
{
try
{
await Task.Delay(TimeSpan.FromMinutes(5));
Sendafter5mins(param1,params2);
}
catch (Exception e)
{
// handle exception
}
}

Catching Error when using Task.Factory

i am using the following
Task.Factory.StartNew(() => DoPrintConfigPage(serial));
then the function i am calling looks like this
private void DoPrintConfigPage(string serial)
{
//do printing work
}
My problem is an exception is being thrown inside the thread and not being handled.
I have tried wrapping it in a try catch
try
{
Task.Factory.StartNew(() => DoPrintConfigPage(serial));
}
catch (Exception ex) { }
but it still is not catching the error and thus crashing the application.
How can I catch exceptions in the main thread so I can handle them?
Update
I have made the changes recommended below and still it is saying the exception is unhandled
var task = Task.Factory.StartNew(() => DoPrintConfigPage(serial))
.ContinueWith(tsk =>
{
MessageBox.Show("something broke");
},TaskContinuationOptions.OnlyOnFaulted);
then in my DoConfigPage I added another try catch.
In this catch is now where it is crashing and saying the exception being thrown was unhandled, what am I missing?
private void DoPrintConfigPage(string serial)
{
try
{
//call the print function
}
catch (Exception ex)
{
throw ex; //it is crashing here and saying it is unhandled
}
}
I also tried what Eric J. suggested with the same results
var task = Task.Factory.StartNew(() => DoPrintConfigPage(serial));
try
{
task.Wait();
}
catch (AggregateException ex) { MessageBox.Show("something broke"); }
Alternatively, you can chain your task creation and add a ContinueWith:
var job = Task.Factory
.StartNew(...)
.ContinueWith(tsk =>
{
// check tsk for exception and handle
});
EDIT: This snippet, when run, pops up the message box for me:
void Main()
{
var serial = "some serial";
var task = Task.Factory
.StartNew(() => DoPrintConfigPage(serial))
.ContinueWith(tsk =>
{
MessageBox.Show("something broke");
var flattened = tsk.Exception.Flatten();
// NOTE: Don't actually handle exceptions this way, m'kay?
flattened.Handle(ex => { MessageBox.Show("Error:" + ex.Message); return true;});
},TaskContinuationOptions.OnlyOnFaulted);
}
public void DoPrintConfigPage(string serial)
{
throw new Exception("BOOM!");
}
Your try block is exited right after you start the new task, because that method just continues to run.
Instead you can catch the Exception as an AggregateException where you wait for the task (or multiple tasks) to complete:
var task1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("I'm bad, but not too bad!");
});
try
{
task1.Wait();
}
catch (AggregateException ae)
{
// Assume we know what's going on with this particular exception.
// Rethrow anything else. AggregateException.Handle provides
// another way to express this. See later example.
foreach (var e in ae.InnerExceptions)
{
if (e is MyCustomException)
{
Console.WriteLine(e.Message);
}
else
{
throw;
}
}
}
http://msdn.microsoft.com/en-us/library/dd997415.aspx
If you are not waiting on your task, I think the easiest solution is found in Task.Exception:
Gets the AggregateException that caused the Task to end prematurely.
If the Task completed successfully or has not yet thrown any
exceptions, this will return null.
I am using something like this:
Task.Factory.StartNew(() => DoStuffHere())
.ContinueWith(task =>
{
if (task.Exception != null)
Log("log all the exceptions!");
});
You should also know about
System.Threading.Tasks.TaskScheduler.UnobservedTaskException.
If you are in the business of creating "fire and forget" Task instances, you'll want to subscribe to that event at the start of your program.
Maybe you are trying to catch a Corrupted State Exception. Since .NET 4 applications are unable to catch such exceptions by default. You could try to add the legacyCorruptedState­­ExceptionsPolicy=true entry to your configuration file as stated in the MSDN article linked above.

Categories