I am using Task.Factory.StartNew to make the long processing service calls off the UI thread.However, i am getting the follwing exception as soon as i load the application,
A task's exception were not observed either by waiting on the Task or accessing its Exception property. As a result the unhandled exception was rethrown by the finalizer thread.
Task.Factory.StartNew(() => this.InitializeViewModel(myViewModel));
private void InitializeViewModel(IModel myViewModel)
{
lock (viewModelLock)
{
myViewModel.MyContext = this.MyContext; // this will set the MyContext property which in turn makes some service calss
}
}
here i can't use task.wait() b'coz then it will cause the wait on the UI thread..
how can i avoid this exception??
Thanks.
as a first workaround/debugging-help wrap your lock (...) inside a try-catch and set a breakpoint inside the catch-Block - this way you should be able to see the problem
To the problem with the Task.Wait - you can use the ContinueWith method to get the exceptions:
var task = Task.Factory.StartNew(() => this.InitializeViewModel(myViewModel));
task.ContinueWith(o => MyErrorHandler(task.Exception), TaskContinuationOptions.OnlyOnFaulted);
don't forget the handler:
void MyErrorHandler(Exception error)
{
// handle the exception (log, or whatever)
}
Related
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'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 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.
I have bunch of Asynchronous commands. I want to write try..catch without much of repeating. Example:
_fooCommand = new AsynchronousCommand( () => { action } );
_barCommand = new AsynchronousCommand( () => { action } );
AsynchronousCommand is class that invokes Action using ThreadPool.QueueUserWorkItem( (state) => { action() } );.
Try..catch works well when is inside lambda:
_fooCommand = new AsynchronousCommand( () => { try.exception.catch } );
When outside then not:
try
_fooCommand = new AsynchronousCommand( () => {...} );
catch
Exception is not catched.
Edit
I want to catch Exception not when creating command: when executing it using command.DoExecute(this) and if possible put try..catch inside lambda.
Exceptions propagate up the call stack on the thread on which they are thrown. Because the commands run on a thread pool thread, it will be on a different thread to your try ... catch hence it doesn't get caught.
EDIT: Assuming you do actually invoke the command within the try ... catch
You can get these semantics through the use of await. It when you await something it will schedule the remainder of the method as a continuation of the previous method, meaning that the operation is performed asynchronously. However, when the awaited operation finishes, if it represents something that throws an exception, that exception will be caught and then re-thrown within the context of your next continuation, allowing you to wrap a series of asynchronous operations in a single try/catch, having the syntax and semantics you desire. A simple example might look like:
public static async Task Foo()
{
try
{
await Task.Run(() => DoSomething());
await Task.Run(() => DoSomethingElse());
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
Here DoSomething and DoSomethingElse will be run in a thread pool thread, and if either throws an exception when running, not when being started, then the catch block will be hit.
I am trying to prevent a task from continuing if the first part fails.
My code looks like that:
Task listener = Task.Factory.StartNew(openConnection).ContinueWith((t) => listenForNumber());
void openConnection()
{
try
{
//stuff
}
catch
{
//morestuff
}
}
void listenForNumber()
{
//even more stuff
}
Now listenForNuber() should not be executed if openConnection() enters the catch block
I tried ContinueWith((t) => listenForNumber(),TaskContinuationOptions.NotOnFaulted);
But no success, any help? :(
Thanks
TaskContiuationOptions.NotOnFaulted will obviously have no effect unless your method has faulted, i.e. an exception thrown during its execution was unhandled.
In your catch block, you should re-throw the exception (and preserve the stack trace) using the throw; statement after you've performed your work (some clean-up maybe) - otherwise the exception won't be thrown again, so your method will not be considered as 'faulted'.
Create an extension method helper.
public static void PropagateExceptions(this Task task)
{
if (task == null)
throw new ArgumentNullException("task");
if (!task.IsCompleted)
throw new InvalidOperationException("The task has not completed yet.");
if (task.IsFaulted)
task.Wait();
}
then call PropagateExceptions() extension method before executing any codes. PropagateExceptions() method will also rethrow if the task was cancelled.
t1.ContinueWith(t => {
t.PropagateExceptions();
listenForNumber();
});
You need to throw the exception in your task method. The TPL does not know the method has failed, unless it catches an exception.
You will still need to have a continuation method for the faulted case. This could be a simple method that logs the exception.
If you don't have a continuation method for the exception, you will get unhandled exceptions in your application when your task method throws an exception.