I'm trying to implement exception handling from a task but I just can't seem to get it right. I've found a few examples of the pattern but no matter what I try I always seem to get unhandled exceptions from within the task itself. I must be missing something, but I can't see what. Any help would be very much appreciated.
I've tried an example I found on MSDN but that doesn't work for me:
https://msdn.microsoft.com/en-us/library/dd997415(v=vs.110).aspx
And I followed the answer to this question but when I run the fix in Visual Studio it still complains about unhandled exceptions:
ContinueWith TaskContinuationOptions.OnlyOnFaulted does not seem to catch an exception thrown from a started task
This is the code that I initially wrote:
static void Main(string[] args)
{
TestAsync().ContinueWith(t =>
{
Console.WriteLine(t.Exception.ToString());
}, TaskContinuationOptions.OnlyOnFaulted);
Console.ReadKey();
}
static async Task<IEnumerable<string>> TestAsync()
{
IEnumerable<string> list = null;
try
{
list = await TestTask();
}
catch (Exception)
{
Console.WriteLine("Caught!");
}
return list;
}
static Task<IEnumerable<string>> TestTask()
{
var task = new Task<IEnumerable<string>>(() =>
{
throw new AggregateException("This is a test");
});
task.Start();
return task;
}
Just hit continue after VS breaks, you will see it gets to your ContinueWith. It is just a quirk of the debugger because it cannot find a try/catch within your code that handles the execption.
If you don't want the debugger to stop and show you a message you will need to disable "Just My Code" in the debugger options so that the try/catch that lives inside of Task gets counted as the thing that catches the exception.
Related
I try to start some action in background, I am not interested in its result, but in case of an error I'd like to log it, and - of course - prevent the application (here: a Windows service) from crashing.
public static void CreateAndStartTaskWithErrorLogging(Action _action, string _componentName, string _originalStacktrace = null)
{
DateTime started = HighPrecisionClock.Now;
Task task = new Task(_action);
task.ContinueWith(_continuation => _continuation.LogExceptions(_componentName, started, _originalStacktrace));
task.ConfigureAwait(false);
task.Start();
}
internal static void LogExceptions(this Task _t, string _componentName, DateTime _started, string _originalStacktrace = null)
{
try
{
_t.Wait(1000);
}
catch (Exception ex)
{
Logger.LogError(_componentName, $"An exception occurred in a fire-and-forget task which was started at {_started}.\r\n" +
$"The original stack trace is:\r\n{_originalStacktrace}");
Logger.LogException(_componentName, ex);
}
try
{
_t.Dispose();
}
catch (Exception dex)
{
Logger.LogException(_componentName, dex);
}
}
Without ConfigureAwait(false) and without _t.Dispose(), the catch works and logs the exception. But the application crashes several seconds later (i.e. on the Finalizer thread?). The entry in the Microsoft Event Viewer shows that exception.
With ConfigureAwait and _t.Dispose(), I do not see the exception in the logs, the application just crashes.
What's wrong with the idea shown above?
Edit:
Meanwhile I tested without ConfigureAwait but with _t.Dispose. I could catch about 10 such exceptions, and none made the application crash. That seems to solve the issue, but I do not understand the reason for that, so the situation is still bad.
What does ConfigureAwait(false) do to Exceptions in the task (or in tasks started within that task, e.g. by a Parallel.ForEach further down)?
Why does the Dispose - which is called on the continuation, not the task proper according to a comment - prevent the crash (the Finalizer does not call Dispose, but Dispose may set some flags influencing its behavior)?
Edit 2:
Also that does not work all the time, only most of the time. Suggested solution 1 below also fails sometimes.
In the crashing context, the function is called with Utilities.TaskExtensions.CreateAndStartTaskWithErrorLogging(() => DataStore.StoreSyncedData(data), Name);, where DataStore is set to a composite which in turn calls Parallel.ForEach(m_InnerDataStores, _store => { _store.StoreSyncedData(_syncedData); }); on its members. One of them writes a video with the Accord library, which sometimes causes an AccessViolation at <Module>.avcodec_encode_video2(libffmpeg.AVCodecContext*, libffmpeg.AVPacket*, libffmpeg.AVFrame*, Int32*), i.e. the exception may come from non-managed code.
Of course, I could try to catch it somewhere down there - but that's not the objective of this method. I expect it to be able to safely run any code in the background without crashing the application.
This is my suggestion for logging errors:
public static void OnExceptionLogError(this Task task, string message)
{
task.ContinueWith(t =>
{
// Log t.Exception
}, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
}
Usage example:
var task = Task.Run(action);
task.OnExceptionLogError("Oops!");
try
{
await task;
}
catch
{
// No need to log exception here
}
I have this code:
//note that this Action is a very time consuming process so I need to wrap it in Task.Run
private static async Task RunBeforeCompletion(Action action)
{
var task = Task.Run(() =>
{
Console.WriteLine("start");
action(); //some exception could have happened here, or I could have used the Task incorrectly that results in exception
//how to catch this exception?
});
await task.ContinueWith(t =>
{
Console.WriteLine(t.Exception.Message);
ExceptionDispatchInfo.Capture(t.Exception.InnerException).Throw();
},
TaskContinuationOptions.OnlyOnFaulted);
}
private static void Sleep()
{
Console.WriteLine("sleep");
Thread.Sleep(1000);
}
private static void RunAll()
{
var tsk = RunBeforeCompletion(Sleep)
.ContinueWith(t1 =>
{
Console.WriteLine("run");
});
Task.WaitAll(tsk);
}
static void Main(string[] args)
{
RunAll();
}
Note that the Action is a very time consuming process so I need to wrap it in Task.Run
Which works fine. The code can run well without exception if there is no exception thrown from the Action
However, if I move the method body of RunBeforeCompletion to another method, then a TaskCanceledException will be thrown. ie: the following code will throw a TaskCanceledException.
private static async Task WrapTask(Action action)
{
var task = Task.Run(() =>
{
Console.WriteLine("start");
action(); //some exception could have happened here, or I could have used the Task incorrectly that results in exception
//how to catch this exception?
});
await task.ContinueWith(t =>
{
Console.WriteLine(t.Exception.Message);
ExceptionDispatchInfo.Capture(t.Exception.InnerException).Throw();
},
TaskContinuationOptions.OnlyOnFaulted);
}
private static async Task RunBeforeCompletion(Action action)
{
await WrapTask(action);
}
private static void Sleep()
{
Console.WriteLine("sleep");
Thread.Sleep(1000);
}
private static void RunAll()
{
var tsk = RunBeforeCompletion(Sleep)
.ContinueWith(t1 =>
{
Console.WriteLine("run");
});
Task.WaitAll(tsk);
}
static void Main(string[] args)
{
RunAll();
}
From what I understand, this is because TaskContinuationOptions.OnlyOnFaulted only works in a single task and not multi-task continuation.
Do note that the crash will only happen when I run the second case code in VS 2015 with debugger attached and with Exception Settings-> Break at all Exception.
If I run without a debugger, or if I don't require the VS to break when TaskCanceledException is thrown, then no problem. Whatever it is, TaskCanceledException should never be thrown.
First question:
But aren't the first and second method the same? I just move the original Task in a separate method.
I believe that I should always be using the TaskContinuationOptions.OnlyOnFaulted option on a single task only as per guideline, that's why I put it immediately after a Task.Run, so that I know that I don't unconsciously chain it with other ContinueWith statement right after a Task.Run.
And what does this mean? Why the TaskCanceledException is thrown with debugger attached but not thrown if no debugger? In that case, how can I be sure all the tasks are finishing successfully or not?
What purpose I'm trying to accomplish?
During action, some exceptions can be thrown, or I might use the Task channing incorrectly, so I want to log the exception first ( using Console.WriteLine as a stub in for this toy example), before I rethrow the exception up for further handling. This is because any exceptions thrown inside Task.Run ( or anything to do with Task) will be swallowed up and later will result in a very mysterious crash. So I want to log the exception.
So my second question is, given that if the user of WrapTask can chain the method up with other ContinueWith construct for as long as he wants, how to write the exception handling code ( for the purpose of logging the exception error) elegantly?
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.
I am trying to get more familiar with async/await programming and exception handling.
static void Main(string[] args)
{
TestAsyncException();
}
private static async void TestAsyncException()
{
try
{
var result = await Task.Factory.StartNew(() => DoSomething());
//do something with the result
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static int DoSomething()
{
throw new Exception("Exception was thrown!");
}
I am expecting the Exception to be handled gracefully but instead the code execution stops and I get
An exception of type 'System.Exception' occurred in .. but was not
handled in user code.
But then when I continue executing the code the Exception actually gets caught (and the message is displayed to the Console).
How am I supposed to catch the Exception without breaking the execution of my code?
First of all, your exception is handled. I believe you are seeing the code stop execution and display the error because you have Break When Thrown on for exceptions. Check your Exception Window (Debug -> Windows -> Exception Settings).
When you use a return type of void on an async method, you lack the ability to get any sort of information back from the method - it's fire and forget. Except in specific situations, this is bad practice. Always have your async methods return a Task or Task<T>:
private static async Task TestAsyncException()
Now, your main method can listen to the task:
static void Main(string[] args)
{
TestAsyncException().Wait(); // or whatever you want to do with the task
Console.Read();
}
Normally, you could use await to unwrap the task here, but that's not allowed in the application entry point.
I have a multithreaded .Net App developed in Mono (Xamarin) with a lot of background async-running Tasks
public Task UpdateAsync()
{
return Task.Run (() => {
.....
});
}
My issue is that one of the Task fails at some random point and crashes and closes the application without any error and no breakpoint triggers. I haven't been able to pinpoint the issue and its really hard since there alot of running async Tasks.
Is there a way to find what Method and line the issue is or even better break at that point?
EDIT:
i also tried registering UnhandledException as suggested below , but it still not handling any errors, the app just closes without any trace
AppDomain.CurrentDomain.UnhandledException += (o, e) =>{ Debugger.Break(); }
EDIT2:
i finally found the issue thanks to all the help here. Is it possible to suggest a way to prevent this (make the debugger break , not app crash) by altering the code below?
public Task StagedUpdateAsync()
{
return Task.Run (() => {
.
.
.
InvokeOnMainThread (() =>
{
// somehow here it was trying to use a null object
// and application crashed
});
});
}
First of all, I want to note that the Tasks themselves do not raise the exceptions from their inner code until they are directly being asked for a Result property or Wait* method or any other blocking methods, so the perfect place to search the exception is the resulting part of your code.
MSDN has a perfect article regarding the exception handling for the Tasks, you should go through it to select your own way to handle exception. I'll reproduce the main ideas from article here, but you suggest you to read the whole article:
try/catch block, easiest for the writing, but if you have a lot of tasks, it can be challenging to select a place for it in your code. Note that you should catch the AggregateException as a wrapper for inner exception, like this:
var task1 = Task.Run( () => { throw new CustomException("This exception is expected!"); } );
try
{
task1.Wait();
}
catch (AggregateException ae)
{
// foreach here
}
Wait for the task to complete and examine it's state:
var task1 = Task.Run( () => { throw new CustomException("This exception is expected!"); } );
while(! task1.IsCompleted) {}
if (task1.Status == TaskStatus.Faulted)
{
// foreach here
}
If your code is creating some inner tasks (either attached or not), or you are creating an array of tasks, they can also raise the exceptions, and you should examine the flatten version of the AggregateException:
try {
task1.Wait();
}
catch (AggregateException ae) {
throw ae.Flatten();
}
try {
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ae) {
throw ae.Flatten();
}
Use the tasks continuation for filtering the faulted ones (note that the exception is still an AggregateException one:
var task1 = Task.Run(() =>
{ throw new CustomException("task1 faulted.");
}).ContinueWith(t => { Console.WriteLine("{0}: {1}",
t.Exception.InnerException.GetType().Name,
t.Exception.InnerException.Message);
}, TaskContinuationOptions.OnlyOnFaulted);
If you're still missing the exception, use the UnobservedTaskException event for the TaskScheduler you are using, similar to one you're trying to handle in AppDomain (event args is an UnobservedTaskExceptionEventArgs):
TaskScheduler.Default.UnobservedTaskException += (o, e) => {
Console.WriteLine(e.Exception.ToString());
Debugger.Break();
}
// or
TaskScheduler.Current.UnobservedTaskException += (o, e) => {
Console.WriteLine(e.Exception.ToString());
Debugger.Break();
}
You could try adding this:-
AppDomain.CurrentDomain.UnhandledException += (o,e) =>{ Debugger.Break();}
And then examine e to see what the exception is, you should be able to open the threads window and switch to the thread thats causing the issue and then step back using the call stack.
For me this sounds very much like an async void issue. Read up on it here, it basically says:
In short, exceptions thrown when calling an async void method isn't handled the same way as awaiting a Task and will crash the process. Not a great experience.
Especially not a great experience since you won't be able to catch it in the debugger. Probably the problem you're experiencing right now. So I'd suggest you to go hunt your async void methods down. Now the problem is that async void methods can be obvious to spot
public async void Foo()
{
await Task.Run(() => {});
}
or well hidden behind a lambda
Action foo = async () => await Task.Run(() => {});
so it becomes a pretty tedious task to flag them down in a larger codebase. Fortunately the author of the before mentioned article provides an automized solution to search for async void signatures based on reflection. Go check it out.
If you're using Visual Studio 2015 you also might use a code analyzer based on Roslyn. There's one especially for async/await available on GitHub.
Both approaches also work well in order to avoid the problem in the future by regulary checking the codebase for async void signatures.
Good luck!