I have a GUI application, in which I want to run something in a task, so it will not hold the UI. I want un unhandled exception in the task to be propogated to the application level exception handler.
However:
If I just throw an exception in the task it will not reach app level
exceptions unless I use wait/await
Async/Await - I call the method from a UI constructor, so I can't use async/await there, since I need to continue with the consturction. I just want to run the task and forget.
I was thinking about using dispatcher.invoke, what do you think?
public MainWindow()
{
InitializeComponent();
MyMethodAsync();
InitializeA();
IntiializeB();
}
private void MyMethodAsync()
{
Task t = Task.Run(() =>
{
//Do some stuff
throw new Exception("Throwing some unexpected exception");
}).ContinueWith(MyContinueWith);
}
private void MyContinueWith(Task task)
{
if (task.IsFaulted && task.Exception != null)
{
dispatcher.BeginInvoke(new Action(() =>
{
throw task.Exception;
}), null);
}
}
Two ways I can think of. First, is register to TaskScheduler.UnobservedTaskException event and log whatever you need there:
private void MyMethodAsync()
{
// Note you should probably register only once, so this may not fit here.
TaskScheduler.UnobservedTaskException += (s, e) => GlobalLogger.Log(e);
Task t = Task.Run(() =>
{
// Do some staff
}).ContinueWith(MyContinueWith);
}
The better option which for some reason you don't want to use, is to actually await the operation and wrap it in a try-catch:
private async Task MyMethodAsync()
{
try
{
await Task.Run(() =>
{
// Do some staff
});
InvokeContinuation();
}
catch (Exception e)
{
// Log.
}
}
Do realize that by calling Task.Run you are generally spawning a new thread which is not likely what you want most of the time. Creating new threads makes sense in some instances where you are doing CPU bound work and in those cases you'll want to consider leveraging other Parallel computation libraries to get the most out of it. Instead if your work is I/O bound you should be able to use asynchronous calls all the way down.
In order to wait for the result of a async method call or an exception bubbled up to the call point you can always tack on a call to ContinueWith to the a task that is returned by the async method. If you are handling both the result and any possible exceptions then async/await semantics work nice. Note however that the code that executes in these continuations may not execute in the same thread as the original thread by default.
Related
In my project, I reference types and interfaces from a dynamic link library.
The very first thing I have to do when using this specific library is to create an instance of EA.Repository, which is defined within the library and serves as kind of an entry point for further usage.
The instantiation EA.Repository repository = new EA.Repository() performs some complex stuff in the background, and I find myself confronted with three possible outcomes:
Instantiation takes some time but finishes successfully in the end
An exception is thrown (either immediately or after some time)
The instantiation blocks forever (in which case I'd like to cancel and inform the user)
I was able to come up with an asynchronous approach using Task:
public static void Connect()
{
// Do the lengthy instantiation asynchronously
Task<EA.Repository> task = Task.Run(() => { return new EA.Repository(); });
bool isCompletedInTime;
try
{
// Timeout after 5.0 seconds
isCompletedInTime = task.Wait(5000);
}
catch (Exception)
{
// If the instantiation fails (in time), throw a custom exception
throw new ConnectionException();
}
if (isCompletedInTime)
{
// If the instantiation finishes in time, store the object for later
EapManager.Repository = task.Result;
}
else
{
// If the instantiation did not finish in time, throw a custom exception
throw new TimeoutException();
}
}
(I know, you can probably already spot a lot of issues here. Please be patient with me... Recommendations would be appreciated!)
This approach works so far - I can simulate both the "exception" and the "timeout" scenario and I obtain the desired behavior.
However, I have identified another edge case: Let's assume the instantiation task takes long enough that the timeout expires and then throws an exception. In this case, I sometimes end up with an AggregateException saying that the task has not been observed.
I'm struggling to find a feasible solution to this. I can't really cancel the task when the timeout expires, because the blocking instantiation obviously prevents me from using the CancellationToken approach.
The only thing I could come up with is to start observing the task asynchronously (i.e. start another task) right before throwing my custom TimeoutException:
Task observerTask = Task.Run(() => {
try { task.Wait(); }
catch (Exception) { }
});
throw new TimeoutException();
Of course, if the instantiation really blocks forever, I already had the first task never finish. With the observer task, now I even have two!
I'm quite insecure about this whole approach, so any advice would be welcome!
Thank you very much in advance!
I'm not sure if I fully understood what you're trying to achieve, but what if you do something like this -
public static void Connect()
{
Task<EA.Repository> _realWork = Task.Run(() => { return new EA.Repository(); });
Task _timeoutTask = Task.Delay(5000);
Task.WaitAny(new Task[]{_realWork, timeoutTask});
if (_timeoutTask.Completed)
{
// timed out
}
else
{
// all good, access _realWork.Result
}
}
or you can even go a bit shorter -
public static void Connect()
{
Task<EA.Repository> _realWork = Task.Run(() => { return new EA.Repository(); });
var completedTaskIndex = Task.WaitAny(new Task[]{_realWork}, 5000);
if (completedTaskIndex == -1)
{
// timed out
}
else
{
// all good, access _realWork.Result
}
}
You can also always call Task.Run with a CancellationToken that will time out, but that will raise an exception - the above solutions give you control of the behaviour without an exception being thrown (even though you can always try/catch)
Here is an extension method that you could use to explicitly observe the tasks that may fail while unobserved:
public static Task<T> AsObserved<T>(this Task<T> task)
{
task.ContinueWith(t => t.Exception);
return task;
}
Usage example:
var task = Task.Run(() => new EA.Repository()).AsObserved();
I've been trying to write an MVVM screen for a WPF application, using the async & await keywords to write asynchronous methods for 1. Initially loading data, 2. Refreshing the data, 3. Saving changes and then refreshing. Although I have this working, the code is very messy and I can't help thinking that there must be a better implementation. Can anyone advise on a simpler implementation?
This is a cut-down version of my ViewModel:
public class ScenariosViewModel : BindableBase
{
public ScenariosViewModel()
{
SaveCommand = new DelegateCommand(async () => await SaveAsync());
RefreshCommand = new DelegateCommand(async () => await LoadDataAsync());
}
public async Task LoadDataAsync()
{
IsLoading = true; //synchronously set the busy indicator flag
await Task.Run(() => Scenarios = _service.AllScenarios())
.ContinueWith(t =>
{
IsLoading = false;
if (t.Exception != null)
{
throw t.Exception; //Allow exception to be caught on Application_UnhandledException
}
});
}
public ICommand SaveCommand { get; set; }
private async Task SaveAsync()
{
IsLoading = true; //synchronously set the busy indicator flag
await Task.Run(() =>
{
_service.Save(_selectedScenario);
LoadDataAsync(); // here we get compiler warnings because not called with await
}).ContinueWith(t =>
{
if (t.Exception != null)
{
throw t.Exception;
}
});
}
}
IsLoading is exposed to the view where it is bound to a busy indicator.
LoadDataAsync is called by the navigation framework when the screen is first viewed, or when a refresh button is pressed. This method should synchronously set IsLoading, then return control to the UI thread until the service has returned the data. Finally throwing any exceptions so they can be caught by the global exception handler (not up for discussion!).
SaveAync is called by a button, passing updated values from a form to the service. It should synchronously set IsLoading, asynchronously call the Save method on the service and then trigger a refresh.
There are a few problems in the code that jump out to me:
Usage of ContinueWith. ContinueWith is a dangerous API (it has a surprising default value for its TaskScheduler, so it should really only be used if you specify a TaskScheduler). It's also just plain awkward compared to the equivalent await code.
Setting Scenarios from a thread pool thread. I always follow the guideline in my code that data-bound VM properties are treated as part of the UI and must only be accessed from the UI thread. There are exceptions to this rule (particularly on WPF), but they're not the same on every MVVM platform (and are a questionable design to begin with, IMO), so I just treat VMs as part of the UI layer.
Where the exceptions are thrown. According to the comment, you want exceptions raised to Application.UnhandledException, but I don't think this code will do that. Assuming TaskScheduler.Current is null at the start of LoadDataAsync/SaveAsync, then the re-raising exception code will actually raise the exception on a thread pool thread, not the UI thread, thus sending it to AppDomain.UnhandledException rather than Application.UnhandledException.
How the exceptions are re-thrown. You'll lose your stack trace.
Calling LoadDataAsync without an await. With this simplified code, it'll probably work, but it does introduce the possibility of ignoring unhandled exceptions. In particular, if any of the synchronous part of LoadDataAsync throws, then that exception would be silently ignored.
Instead of messing around with the manual-exception-rethrows, I recommend just using the more natural approach of exception propagation through await:
If an asynchronous operation fails, the task gets an exception placed on it.
await will examine this exception, and re-raise it in a proper way (preserving the original stack trace).
async void methods do not have a task on which to place an exception, so they will re-raise it directly on their SynchronizationContext. In this case, since your async void methods run on the UI thread, the exception will be sent to Application.UnhandledException.
(the async void methods I'm referring to are the async delegates passed to DelegateCommand).
The code now becomes:
public class ScenariosViewModel : BindableBase
{
public ScenariosViewModel()
{
SaveCommand = new DelegateCommand(async () => await SaveAsync());
RefreshCommand = new DelegateCommand(async () => await LoadDataAsync());
}
public async Task LoadDataAsync()
{
IsLoading = true;
try
{
Scenarios = await Task.Run(() => _service.AllScenarios());
}
finally
{
IsLoading = false;
}
}
private async Task SaveAsync()
{
IsLoading = true;
await Task.Run(() => _service.Save(_selectedScenario));
await LoadDataAsync();
}
}
Now all the problems have been resolved:
ContinueWith has been replaced with the more appropriate await.
Scenarios is set from the UI thread.
All exceptions are propagated to Application.UnhandledException rather than AppDomain.UnhandledException.
Exceptions maintain their original stack trace.
There are no un-await-ed tasks, so all exceptions will be observed some way or another.
And the code is cleaner, too. IMO. :)
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!
If I have an application with a synchronous method, is it safe to call an async method as shown below on a UI thread or is there an issue or potential deadlock situation? I know that calling Wait will obviously cause issues, but I feel like this may work out alright.
public void MyMainMethod(){
var getResult = Task.Run(async () => { await getResultAsync(); }).Result;
myLabel.Text = getResult;
}
I can successfully run on a UI thread without issue, but I feel as if I may be missing something. I understand that I could use a Task and ContinueWith, but in this example, I would want to wait for the result of the async method before exiting the synchronous method.
Update / Clarification
In the example above, let's assume that the MyMainMethod is an overridden method or a property, etc. and cannot be modified to be async.
Let's look at your code:
public void MyMainMethod(){
var getResult = Task.Run(async () => { await getResultAsync(); }).Result;
myLabel.Text = getResult;
}
Regardless of what's taking place inside getResultAsync, this code is blocking the UI thread when it calls task.Result. In most cases, this is already wrong.
Further, the fact that your getResultAsync is async suggests there's already an async operation inside it. There is no reason to wrap it with Task.Run, unless you perform a mix of CPU- and IO- bound tasks inside getResultAsync. Even then, it may not be necessary (see this for more details).
You can control the await continuation context inside getResultAsync with ConfiureAwait(false), and should do so to avoid deadlocks and redundant context switches, where possible.
So, the code can be reduced to:
public void MyMainMethod(){
var getResult = getResultAsync().Result;
myLabel.Text = getResult;
}
As is, it still blocks the UI. To avoid blocking, you need to make it async. See Async All the Way from Best Practices in Asynchronous Programming by Stephen Cleary.
If it cannot be modified to be async (as clarified in the update to your question), then the above is the best you can get. Indeed, it still may cause a deadlock, depending on what's going on inside getResultAsync, with out without Task.Run. To avoid deadlocks, you should not attempt to access the UI thread with a synchronous call like control.Invoke inside getResultAsync, or await any tasks scheduled on the UI thread with TaskScheduler.FromCurrentSynchronizationContext.
However, usually it is possible and desirable to re-factor the code like this into an async version:
public async Task MyMainMethod(){
var getResult = await getResultAsync();
myLabel.Text = getResult;
}
You would be calling it from a top-level entry point of your app, like a UI event handler:
async void Button_Click(object sender, EventArg e)
{
try
{
await MyMainMethod();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
it better to call your ui update through dispatcher.
Task task = LoadTask();
task.ContinueWith(t =>
Dispatcher.BeginInvoke(() => UpdateUI()));
public async Task LoadTask()
{
Task getdata =
Task.Factory.StartNew(() =>
{
Sleep(3000);
});
await getdata;
return;
}
I have the following code
var exceptions = new ConcurrentQueue<Exception>();
Task task = Task.Factory.StartNew(() =>
{
try
{
Parallel.Invoke(
async () => await _aViewModel.LoadData(_someId),
async () => await _bViewModel.LoadData(_someId)
);
}
catch (Exception ex)
{
exceptions.Enqueue(ex);
}
}).ContinueWith((continuation) =>
{
if (exceptions.Count > 0) throw new AggregateException(exceptions);
});
I am using Task.StartNew here because the LoadData method use the Dispatcher.StartAsync method to invoke on the main UI thread internally.
The problem I have is that if I force _aViewModel.LoadData to throw an exception it is not caught in the Catch(Exception) clause (nor if I catch AggregateException). I don't understand why!?
Parallel.Invoke is not async-aware. So your async lambdas are being converted to async void methods, which have extremely awkward error semantics (they are not allowed to leave the async void method; instead, they are captured and re-raised directly on the SynchronizationContext that was active at the time the async void method started - in this case, the thread pool).
I'm not sure why you have the Parallel.Invoke in the first place. Since your method is already async, you could just do something like this:
Task task = Task.Factory.StartNew(async () =>
{
try
{
Task.WaitAll(
_aViewModel.LoadData(_someId),
_bViewModel.LoadData(_someId)
);
}
catch (Exception ex)
{
exceptions.Enqueue(ex);
}
})...
P.S. If you have the time, rethink the structure of this whole part of the code. Dispatcher.StartAsync is a code smell. The UI should be (asynchronously) requesting data; the data retrieval objects should not have to know about the UI.
Parallel.Invoke takes an array of Action delegates. It has no means of knowing that your delegates are actually async methods, and therefore it returns before your tasks have completed.
For an in-depth explanation of this behaviour, watch Lucian Wischik's Channel 9 video on the subject.
Try changing your code to use the Task.WhenAll method instead.
var aTask = _aViewModel.LoadData(_someId);
var bTask = _bViewModel.LoadData(_someId);
await Task.WhenAll(aTask, bTask);