Exception in async methods is not caught - c#

The following code does not catch my OperationCancelException which is thrown by calling ct.ThrowIfCancellationRequested.
public partial class TitleWindow : Window, IAsyncInitialization
{
public Task Initialization{get; private set;}
CancellationTokenSource cts;
public TitleWindow()
{
InitializeComponent();
cts = new CancellationTokenSource();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
cts.Cancel();
Initialization = GetCancelExceptionAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation canceled!");
}
}
public async Task GetCancelExceptionAsync(CancellationToken ct)
{
await Task.Delay(1000);
ct.ThrowIfCancellationRequested();
}
}
However if i replace my Window_Loaded method with the following (making it async and await the call of my async method), the exception gets caught.
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
cts.Cancel();
await GetCancelExceptionAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation canceled!");
}
}
Why is my first approach not working? Is the exception not properly propagated to the correct synchronization context?
I was trying to use The Asynchronous Initialization Pattern described in Stephen Clearys blog post to be able to later on await a task which was started in a constructor (and in order to make it comparable to my second example I used the (async) Window_Loaded event to await methods there right away, like suggested to me in a previous question). Then I wanted to provide an option to cancel the async method that I started in the constructor, where i am currently stuck because the exception handling does not work as I expected.
With my "non-working" code, I can catch the exception by putting await Initialization in a try-catch block somewhere, but I still get an additional unhandled exception.
How do I implement this in a way that allows me to await my async method later on (to ensure that I do not work with an inconsistent state of my object) and still being able to cancel that long-running Task (which would of course need to return/set default values)?

In your first example the exception is not caught because it does not occure before leaving the try/catch block. If you want to catch it there you need to wait/await it there exactly like you do in the second example.
If you do not await the returned task the method continues execution and leaves the try/catch block before the exception actually occures...
If you want to catch the exception "out of band" you can also register to TaskScheduler.UnobservedTaskException (this event is called if a task is throwing an exception which is nowhere caught) to get all uncaught exceptions or monitor the tasks Exception property. May also check out THIS answer.

Exeption is thrown in the task on another thread.
public async Task GetCancelExceptionAsync(CancellationToken ct)
{
try
{
await Task.Delay(1000);
ct.ThrowIfCancellationRequested();
}
catch (Exception e)
{
// your Cancleation expeption
}
}

Related

Task.Run() doesn't raise exception?

I have the following code in the
private void Button_Click(object sender, EventArgs e)
{
try
{
Task.Run(async () => await Presenter.Search());
}
catch (Exception ex)
{
LabelMessage.Text = "Error:....";
}
}
The function Presenter.Search() may get exceptions in some cases and I want to show an error message. However, the exception is not raised? I can only see it in the Visual studio debugger.
Really this should be written like so:
private async void Button_Click(object sender, EventArgs e)
{
try
{
await Presenter.Search();
}
catch (Exception ex)
{
LabelMessage.Text = "Error:....";
}
}
Now the call is awaited and the exception will be handled correctly. Note that you shouldn't typically use async void for the reasons listed here, but in the case of UI event handlers it's the recommended approach.
First of all, if Presenter.Search already returns a Task you should consider to make the event handler async and simply put
await Presenter.Search();
in the try-catch block.
The reason of Task.Run(Func<Task>) overload exists is that you can force an already existing Task to be scheduled for execution on a pool thread. This case can be justified in very rare cases as normally you should rely on the internal implementation of the Task returning methods. But if you know that an async method does not use threads (for example, just returns a Task, which will be completed on a specific event) and you are confident enough about forcing the execution on a pool thread you can do it this way. But also in this case you should await the external task; otherwise, the call is fire-and-forget and you will not catch anything:
await Task.Run(() => Presenter.Search());
Please note that I omitted the inner async-await:
await Task.Run(async () => await Presenter.Search());
This would also work and is functionally equivalent to the previous version but adds a needless inner state machine to the chain of tasks to execute.
TL;DR: Without knowing any further details await Presenter.Search(); seems to be the better solution but also await Task.Run(() => Presenter.Search()); can be justified if you know what you are doing.

C# async - Exception not handled

This code here is not handling the Exception thrown, when it cant connect to the Server. Any Ideas why? Thanks!
public Form1()
{
InitializeComponent();
StartClient();
}
async private Task StartClient()
{
try
{
await ConnectToServerAsync();
}
catch (System.Net.Sockets.SocketException)
{
MesssageBox.Show("TEST");
}
}
private Task ConnectToServerAsync()
{
return Task.Factory.StartNew(() => client.Connect(host, port));
}
The thing is: "async void" is very dangerous construct that should almost never appear in your production code. Async method is not a list of statements internally, it's kind of state machine that switches from one "await" statement to another, doing various things in-between while "awaiting". So, once you got an exception raised inside that state machine, you need special context to preserve the stack trace etc. Void methods do not provide such a context. Return Task or Task<something> instead.
As a further reading, I could recommend Phil Haack's very nice blogpost: http://haacked.com/archive/2014/11/11/async-void-methods/
There are various problems with this code. First, using async void is only meant for event handlers. An async void method can't be awaited and any exceptions it throws can't be handled. Second, Task.Factory.StartNew(()=>client.Connect(host,port)) fakes asynchronous execution. It still blocks a thread. Asynchronous execution means that no thread is blocked while waiting for the operation to complete.
I assume you use TcpClient. This class already has a ConnectAsync method that connects in an asynchronous manner. You could simplify your code to this:
private async Task StartClient()
{
try
{
await client.ConnectAsync(host,port);
}
catch (Exception exc)
{
MessageBox.Show(exc.ToString());
}
}
If you want to start the client in response to a UI event, eg a button click, you'd write :
async void Button1_Click(object sender, EventArgs e)
{
await StartClient();
}
or
async void Button1_Click(object sender, EventArgs e)
{
try
{
await StartClient();
//Work with the client
}
catch(Exception exc)
{
MessageBox.Show(exc.ToString());
}
}
Finally, use a logging library instead of MessageBox.Show, eg log4net so you don't lose exception messages due to threading issues.

Async Await Equivalent

When I run this code everything works fine:
public async void InvokePlugin(MyObject xTask)
{
try
{
var hndlr = new TimeoutHandler(RunTask);
var asyncResult = hndlr.BeginInvoke(xTask, null, new object());
if (!asyncResult.AsyncWaitHandle.WaitOne(xTask.Timeout, false))
{
throw new TimeoutException("Plugin didn't complete processing in a timely manner.");
}
hndlr.EndInvoke(asyncResult);
}
catch (Exception ex)
{
//Handle Exceptions
}
}
private delegate void TimeoutHandler(MyObject xTask);
I want to update this code to use Async/Await. I tried doing it like this:
public async void InvokePlugin(MyObject xTask)
{
try
{
var runTask = Task.Run(() => { RunTask(xTask); });
if (await Task.WhenAny(runTask, Task.Delay(xTask.Timeout)) == runTask)
{
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await runTask;
}
else
{
throw new TimeoutException("Plugin didn't complete processing in a timely manner.");
}
}
catch (Exception ex)
{
//Handle Exceptions
}
}
...but it's not working. Clearly I'm doing somethign wring. It does call the RunTask Method and executes the first 2 lines fine but then it just ends and I can't seem to catch the exception in either the TaskRun method or code above. All I see in the Output windows is "Program has exited with code 0 (0x0)."
If the experts out there can either point me to what I'm doing wrong or give me suggestions as to how I can catch the exception and handle it I would be very grateful.
Also if you feel I missed any important details please ask and I will update my question.
Usually I'd say if it works don't fix it but in this case I'm trying to rearchitect a bit to allow for some enhancements so here I am.
Change async void to async Task. See my article on async best practices for more information.
After you do this, consume it asynchronously:
await the task, allowing async to grow.
async and await will naturally grow upward through your code base, until they reach Main, which cannot be async.
In your Main method, call GetAwaiter().GetResult() on the "top" task.
Blocking on asynchronous code is generally not a good idea, but blocking on a single task in a Console app's Main method is an exception to that rule.

Async / Await Lambdas

I have a strange problem combining the async/await to make it work:
I created a small procedure, which should handle basically the try/catch of every action:
internal static void HandledAction(Action action, Info infoBar)
{
try
{
action();
}
catch (Exception ex)
{
infoBar.SetError("An Exception occured: " + ex.Message);
WriteLog(ex.StackTrace);
}
Nohing to fancy, but it's worth since changing error-handling is very easy made.
But what happens, if I'd like to get Data async in the Lambda? Lets take this simple example:
private void mnuImportData_Click(object sender, RoutedEventArgs e)
{
ActionHelper.HandledAction(async () =>
{
throw new NotImplementedException("Ups");
}, infoMain);
}
Sure, the HandledAction gets called, passes, since it gets the pointer back, and the exception gets thrown, of course not handled.
I imagine I have to create a AsyncHandledAction, and set the action async, but is there a easier way to solve this problem?
I guess many people use a central exception-handling, and there are far better solutions for this?
Thanks in advance
Matthias
Edit: I created an example, which should shpw netter I need: I basically dont want the whole Action I pass being awaitable, but one call in the Lambda is:
ActionHelper.HandledActionAsync(() =>
{
//elided
CheckFileResult rslt = await excelImport.CheckFilesAsync(tmpPath);
//elided
}, infoMain);
Of course, by doing so, I get the error:
Error 3 The 'await' operator can only be used within an async lambda expression. Consider marking this lambda expression with the 'async' modifier.
The reason is: Action instead of Func. Since yours:
async () =>
{
throw new NotImplementedException("Ups");
}
in fact is:
async void Method() { }
when Func<Task> is:
async Task Method() { }
Async void will capture SynchronizationContext.Current and when exception is thrown it will be posted to SynchronizationContext by SynchronizationContext.Post() - (in windows runtime you can catch these types of exception). In case of ASP.NET/Console application SynchronizationContext.Current returns null which means that exception would be propagated to Thread Pool and I'm not sure but I think it is not possible to catch it. However when there is returned Task by asynchronous method exception could be marshaled to the caller through this returned Task. It is also worth mention that async lambda expresions will always prefer methods with Func<Task> over Action. General rule is: never use async void (async Action) unless it is "top-level method" (in example event handler).
You need an async version of HandleAction
internal static async Task HandledAction(Func<Task> action, Info infoBar)
{
try
{
await action();
}
catch (Exception ex)
{
infoBar.SetError("An Exception occured: " + ex.Message);
WriteLog(ex.StackTrace);
}
}
of course you should call the method with await
private async void mnuImportData_Click(object sender, RoutedEventArgs e)
{
await ActionHelper.HandledAction(async () =>
{
throw new NotImplementedException("Ups");
}, infoMain);
}

async/await - when to return a Task vs void?

Under what scenarios would one want to use
public async Task AsyncMethod(int num)
instead of
public async void AsyncMethod(int num)
The only scenario that I can think of is if you need the task to be able to track its progress.
Additionally, in the following method, are the async and await keywords unnecessary?
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
Normally, you would want to return a Task. The main exception should be when you need to have a void return type (for events). If there's no reason to disallow having the caller await your task, why disallow it?
async methods that return void are special in another aspect: they represent top-level async operations, and have additional rules that come into play when your task returns an exception. The easiest way is to show the difference is with an example:
static async void f()
{
await h();
}
static async Task g()
{
await h();
}
static async Task h()
{
throw new NotImplementedException();
}
private void button1_Click(object sender, EventArgs e)
{
f();
}
private void button2_Click(object sender, EventArgs e)
{
g();
}
private void button3_Click(object sender, EventArgs e)
{
GC.Collect();
}
f's exception is always "observed". An exception that leaves a top-level asynchronous method is simply treated like any other unhandled exception. g's exception is never observed. When the garbage collector comes to clean up the task, it sees that the task resulted in an exception, and nobody handled the exception. When that happens, the TaskScheduler.UnobservedTaskException handler runs. You should never let this happen. To use your example,
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
Yes, use async and await here, they make sure your method still works correctly if an exception is thrown.
For more information see: https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming
I have come across this very useful article about async and void written by Jérôme Laban:
https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.html
The bottom line is that an async+void can crash the system and usually should be used only on the UI side event handlers.
The reason behind this is the Synchronization Context used by the
AsyncVoidMethodBuilder, being none in this example. When there is no
ambient Synchronization Context, any exception that is unhandled by
the body of an async void method is rethrown on the ThreadPool. While
there is seemingly no other logical place where that kind of unhandled
exception could be thrown, the unfortunate effect is that the process
is being terminated, because unhandled exceptions on the ThreadPool
effectively terminate the process since .NET 2.0. You may intercept
all unhandled exception using the AppDomain.UnhandledException event,
but there is no way to recover the process from this event.
When writing UI event handlers, async void methods are somehow
painless because exceptions are treated the same way found in
non-async methods; they are thrown on the Dispatcher. There is a
possibility to recover from such exceptions, with is more than correct
for most cases. Outside of UI event handlers however, async void
methods are somehow dangerous to use and may not that easy to find.
The problem with calling async void is that
you don’t even get the task back. You have no way of knowing when the function’s task has completed. —— Crash course in async and await | The Old New Thing
Here are the three ways to call an async function:
async Task<T> SomethingAsync() { ... return t; }
async Task SomethingAsync() { ... }
async void SomethingAsync() { ... }
In all the cases, the function is transformed into a chain of tasks. The difference is what the function returns.
In the first case, the function returns a task that eventually produces the t.
In the second case, the function returns a task which has no product, but you can
still await on it to know when it has run to completion.
The third case is the nasty one. The third case is like the second case, except
that you don't even get the task back. You have no way of knowing when
the function's task has completed.
The async void case is a "fire and
forget": You start the task chain, but you don't care about when it's
finished. When the function returns, all you know is that everything
up to the first await has executed. Everything after the first await
will run at some unspecified point in the future that you have no
access to.
I think you can use async void for kicking off background operations as well, so long as you're careful to catch exceptions. Thoughts?
class Program {
static bool isFinished = false;
static void Main(string[] args) {
// Kick off the background operation and don't care about when it completes
BackgroundWork();
Console.WriteLine("Press enter when you're ready to stop the background operation.");
Console.ReadLine();
isFinished = true;
}
// Using async void to kickoff a background operation that nobody wants to be notified about when it completes.
static async void BackgroundWork() {
// It's important to catch exceptions so we don't crash the appliation.
try {
// This operation will end after ten interations or when the app closes. Whichever happens first.
for (var count = 1; count <= 10 && !isFinished; count++) {
await Task.Delay(1000);
Console.WriteLine($"{count} seconds of work elapsed.");
}
Console.WriteLine("Background operation came to an end.");
} catch (Exception x) {
Console.WriteLine("Caught exception:");
Console.WriteLine(x.ToString());
}
}
}
A brief explanation:
async Task<T> method() await can be used to wait till the execution is completed and it will return value of type T
async Task method() await can be used to wait till the execution is completed but no data is returned
async void method() can't be awaited and no data is returned [Example: async event execution]
My answer is simple
you can not await void method
Error CS4008 Cannot await 'void' TestAsync e:\test\TestAsync\TestAsyncProgram.cs
So if the method is async, it is better to be awaitable, because you can lose the advantage ofasync.

Categories

Resources