Using async/await with Dispatcher.BeginInvoke() - c#

I have a method with some code that does an await operation:
public async Task DoSomething()
{
var x = await ...;
}
I need that code to run on the Dispatcher thread. Now, Dispatcher.BeginInvoke() is awaitable, but I can't mark the lambda as async in order to run the await from inside it, like this:
public async Task DoSomething()
{
App.Current.Dispatcher.BeginInvoke(async () =>
{
var x = await ...;
}
);
}
On the inner async, I get the error:
Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type.
How can I work with async from within Dispatcher.BeginInvoke()?

The other answer may have introduced an obscure bug. This code:
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
uses the Dispatcher.Invoke(Action callback) override form of Dispatcher.Invoke, which accepts an async void lambda in this particular case. This may lead to quite unexpected behavior, as it usually happens with async void methods.
You are probably looking for something like this:
public async Task<int> DoSomethingWithUIAsync()
{
await Task.Delay(100);
this.Title = "Hello!";
return 42;
}
public async Task DoSomething()
{
var x = await Application.Current.Dispatcher.Invoke<Task<int>>(
DoSomethingWithUIAsync);
Debug.Print(x.ToString()); // prints 42
}
In this case, Dispatch.Invoke<Task<int>> accepts a Func<Task<int>> argument and returns the corresponding Task<int> which is awaitable. If you don't need to return anything from DoSomethingWithUIAsync, simply use Task instead of Task<int>.
Alternatively, use one of Dispatcher.InvokeAsync methods.

I think you can use below code and then depends of place use it with async and await or without to fire and forget:
public static Task FromUiThreadAsync(Action action)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Dispatcher disp = GetUiDispatcher();
disp.Invoke(DispatcherPriority.Background, new Action(() =>
{
try
{
action();
tcs.SetResult(true);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}));
return tcs.Task;
}

Use Dispatcher.Invoke()
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}

(Edit: This answer is wrong, but I'll fix it soon)
Declare this
public async Task DoSomethingInUIThreadAsync(Func<Task> p)
{
await Application.Current.Dispatcher.Invoke(p);
}
Use like this
string someVar = "XXX";
DoSomethingInUIThreadAsync(()=>{
await Task.Run(()=> {
Thread.Sleep(10000);
Button1.Text = someVar;
});
});
DoSomethingInUIThreadAsync receives a delegate that returns a Task, Application.Current.Dispatcher.Invoke accepts a Func callback that can be awaited.

Related

Task.Run fails to process awaited methods

We are running into a situation where have a requirement to start and execute few launch and forget threads during a call. Though, our call fails to execute if the async methods have any awaited call.
Here is an example. Are we missing something?
public class SomeClass
{
public async Task Test()
{
//Calling synchronously this things works
await Save(1).ConfigureAwait(false);
await Save(2).ConfigureAwait(false);
await Save(3).ConfigureAwait(false);
//Starting three threads at the same time fails while trying to run var queryResult = await SomeClient.QueryAsync<T>(q).ConfigureAwait(false);
_ = Task.Run(async () => await Save(1));
_ = Task.Run(async () => await Save(2));
_ = Task.Run(async () => await Save(3));
}
public async Task<bool> Save(int ct)
{
var x = await Update(ct).ConfigureAwait(false);
return x;
}
public async Task<bool> Update(int ct)
{
await _someObject.CallingSomeAsyncMethod<dynamic>("Some Query").ConfigureAwait(false);
await _someObject.CallingSomeAsyncMethod<dynamic>("Some Query").ConfigureAwait(false);
await _someObject.CallingSomeAsyncMethod<dynamic>("Some Query").ConfigureAwait(false);
return true;
}
}
public class SomeObject
{
public async Task<T> CallingSomeAsyncMethod(string q)
{
await Task.Delay(1000).ConfigureAwait(false);
//OR Any async method which is awaited here just stops the execution
return queryResult;
}
}
If you want to run multiple tasks at the same time you should call the methods without the await and hold the task. Then you can do await Task.WhenAll(task1, task2, task3, ...);

c# Writing an async method that doesn't have an await in it

I want to have an async method in my call that would be called by my library consumers with an await. But the internal working of my method, while I need it to run on a separate thread, does not call any other await on it's own.
I just do the work the method is supposed to do and return the type. And the compiler warns me that this method will not run in an async way.
public async Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
}
On the other hand, if I write a method that starts a new task using TaskFactory like this:
public Task<MyResultObject> DoSomeWork()
{
return Task<MyResultObject>.Factory.StartNew(() =>
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
});
}
Then I cannot call it using the await keyword like this await DoSomeWork().
How do I write an async (must be async and not task with result or wait) without using some await call inside?
You can do this
public Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return Task.FromResult(result);
}
which is exactly the same as
public async Task<MyResultObject> DoSomeWork()
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
}
Only this version gives a warning and has slightly more overhead.
But neither will run on another thread. The only benefit is that they have an awaitable interface.
To do it in parallel, your code is Ok but Task.Run is preferred over StartNew():
public Task<MyResultObject> DoSomeWork()
{
return Task.Run(() =>
{
MyResultObject result = new MyResultObject();
// Some work to be done here
return result;
});
}
And in all these cases you can definitely await DoSomeWork()

Chaining async methods

I'm attempting to chain together a few async methods I've created and I believe there is some fundamental misunderstanding on my part about how this works
Here's a representation of my code:
public async Task<bool> LoadFoo()
{
return await Foo.ReadAsync("bar").ContinueWith((bar) =>
{
Foo.ReadAsync("baz").ContinueWith((baz) =>
{
Foo.ReadAsync("qux").ContinueWith((qux) =>
{
return true;
});
return true;
});
return true;
});
}
public void LoadEverything()
{
LoadFoo().ContinueWith((blah) =>
{
OtherLoadMethod();
});
}
Now I was expecting when LoadEverything() was called that all of the ReadAsync methods in LoadFoo ("bar", "baz" and "qux") would run and complete, and after they all completed then the .ContinueWith in LoadEverything would run so that OtherLoadMethod() wouldn't execute until the "bar", "baz" and "qux" ReadAsync methods finished.
What I am actually seeing is that LoadFoo gets called and then OtherLoadMethod starts to run before getting to the final completion in LoadFoo (the ContinueWith of the "qux" ReadAsync).
Can someone help clear up my misunderstanding here? Why wouldn't the execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?
Why wouldn't execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?
Because that's how await works. The continuations you register are just that: continuations. They are not executed synchronously in the current method. You are telling the framework that when the current task completes, the continuation should be executed. The Task object returned by ContinueWith() allows you to observe the completion if and when it happens. There would be no need to even return a Task object, if the ContinueWith() method blocked until the continuation was executed.
Likewise, the Task<bool> returned by your LoadFoo() method represents the overall completion of the method, including the await...ContinueWith() that you're returning. The method returns prior to completion of the continuation, and callers are expected to use the returned task if they need to wait for the continuation to complete.
All that said, I don't understand why you're using ContinueWith() in the first place. You obviously have access to await, which is the modern, idiomatic way to handle continuations. IMHO, your code should look something like this (it's not clear why you're returning Task<bool> instead of Task, since the return value is only ever true, but I assume you can figure that part out yourself):
public async Task<bool> LoadFoo()
{
await Foo.ReadAsync("bar");
await Foo.ReadAsync("baz");
await Foo.ReadAsync("qux");
return true;
}
public async Task LoadEverything()
{
await LoadFoo();
await OtherLoadMethod();
}
You can also use Unwrap:
public async Task<bool> LoadFoo()
{
await Foo.ReadAsync("bar")
.ContinueWith(_ => Foo.ReadAsync("baz")).Unwrap()
.ContinueWith(_ => Foo.ReadAsync("qux")).Unwrap();
return true;
}
public async Task LoadEverything()
{
await LoadFoo().ContinueWith(_ => OtherLoadMethod()).Unwrap();
}
Did not expect the top solution in search engine was fixing a misunderstanding but not actually the solution of the topic itself.
Chaining call can make great context focus when developing, async is good, and it is better if you know what u r doing.
Code:
//thanks for TheodorZoulias's review and input
public static class TaskHelper
{
public static async Task<TOutput> ThenAsync<TInput, TOutput>(
this Task<TInput> inputTask,
Func<TInput, Task<TOutput>> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
return output;
}
public static async Task<TOutput> ThenAsync<TInput, TOutput>(
this Task<TInput> inputTask,
Func<TInput, TOutput> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = continuationFunction(input);
return output;
}
public static async Task<TInput> ThenAsync<TInput>(
this Task<TInput> inputTask,
Action<TInput> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
continuationFunction(input);
return input;
}
public static async Task<TInput> ThenAsync<TInput>(
this Task<TInput> inputTask,
Func<TInput, Task> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
return input;
}
public static async Task<TOutput> ThenAsync<TOutput>(
this Task inputTask,
Func<Task<TOutput>> continuationFunction,
bool continueOnCapturedContext= true)
{
await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = await continuationFunction().ConfigureAwait(continueOnCapturedContext);
return output;
}
public static async Task ThenAsync(
this Task inputTask,
Action continuationFunction,
bool continueOnCapturedContext= true)
{
await inputTask.ConfigureAwait(continueOnCapturedContext);
continuationFunction();
}
}

Testing for exceptions in async methods

I'm a bit stuck with this code (this is a sample):
public async Task Fail()
{
await Task.Run(() => { throw new Exception(); });
}
[Test]
public async Task TestFail()
{
Action a = async () => { await Fail(); };
a.ShouldThrow<Exception>();
}
The code doesn't catch the exception, and fails with
Expected a System.Exception to be thrown, but no exception was
thrown.
I'm sure I'm missing something, but docs seem to suggest this is the way to go. Some help would be appreciated.
You should use Func<Task> instead of Action:
[Test]
public void TestFail()
{
Func<Task> f = async () => { await Fail(); };
f.ShouldThrow<Exception>();
}
That will call the following extension which is used to verify asynchronous methods
public static ExceptionAssertions<TException> ShouldThrow<TException>(
this Func<Task> asyncAction, string because = "", params object[] becauseArgs)
where TException : Exception
Internally this method will run task returned by Func and wait for it. Something like
try
{
Task.Run(asyncAction).Wait();
}
catch (Exception exception)
{
// get actual exception if it wrapped in AggregateException
}
Note that test itself is synchronous.
With Fluent Assertions v5+ the code will be like :
ISubject sut = BuildSut();
//Act and Assert
Func<Task> sutMethod = async () => { await sut.SutMethod("whatEverArgument"); };
await sutMethod.Should().ThrowAsync<Exception>();
This should work.
Other variation of usage ThrowAsync method:
await Should.ThrowAsync<Exception>(async () => await Fail());
With Fluent Assertions v5.7 they introduced the Awaiting overload so now you can do as following:
public async void TestFail()
{
await this.Awaiting(_ => Fail()).Should().ThrowAsync<Exception>();
}
With Fluent Assertions v6.9 you can use short form:
var act = () => Fail();
act.Should().ThrowAsync<Exception>();

Implementing WhenAll on QueueBackgroundWorkItem

I need to spawn some long running tasks in ASP.NET WebAPI, and I chose to do that using QueueBackgroundWorkItem.
My question is -
I need to implement a WhenAll mechanism with those tasks, meaning - I need to know when some tasks has finished, and then to perform some other task.
How can that be done using QueueBackgroundWorkItem? I couldn't find a way to do that, since it returns void, and accepts Action.
Thanks!
You can use TaskCompletionSource to create a helper method like this:
public static Task RunViaQueueBackgroundWorkItem(Action<CancellationToken> action)
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
HostingEnvironment.QueueBackgroundWorkItem((ct) =>
{
try
{
action(ct);
if (ct.IsCancellationRequested)
tcs.TrySetCanceled();
else
tcs.TrySetResult(0);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
This method will return a task that will complete after the action completes. Note that it handles the case where an exception occurs during the invocation of the action. It also handles the case if cancellation is requested.
Here is an example of how you can use it:
public async Task<string> Get(int id)
{
var t1 = RunViaQueueBackgroundWorkItem(ct => DoSomeTask1(ct));
var t2 = RunViaQueueBackgroundWorkItem(ct => DoSomeTask2(ct));
await Task.WhenAll(t1, t2);
//...
}
For completeness, here is the helper method for the other overload of QueueBackgroundWorkItem:
public static Task RunViaQueueBackgroundWorkItem(Func<CancellationToken,Task> asyncAction)
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
HostingEnvironment.QueueBackgroundWorkItem(async (ct) =>
{
try
{
await asyncAction(ct);
if (ct.IsCancellationRequested)
tcs.TrySetCanceled();
else
tcs.TrySetResult(0);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
I need to implement a WhenAll mechanism with those tasks, meaning - I need to know when some tasks has finished, and then to perform some other task.
What you should do is write up the logic you need:
async Task MyWorkAsync(CancellationToken token)
{
var t1 = Work1Async(token);
var t2 = Work2Async(token);
await Task.WhenAll(t1, t2);
... // More work
}
And then just call QueueBackgroundWorkItem once:
HostingEnvironment.QueueBackgroundWorkItem(token => MyWorkAsync(token));

Categories

Resources