How-to: Call await method from a delegate void event method?
Converting (an ASP.NET) app to async is an all in - granted. But what about the places where it is not supported?
var policy = new CacheItemPolicy();
policy.UpdateCallback = CacheEntryUpdateCallback;
void VoidDelegate(CacheEntryUpdateArguments arguments) {
// need this - but no can't do :(
await SomeApi.AsyncOnlyMethodAsync();
}
Await is not allow there, so what to do? What is the right way of doing this? The question also, applies to event handlers on WebForms like myButton.Commmand += new CommandEventHandler(VoidDelegate)
Is it A:
void VoidDelegate(CacheEntryUpdateArguments arguments) {
Task.Factory.StartNew(new Func<Task>(async () => {
await SomeApi.AsyncOnlyMethodAsync();
})).Unwrap().Wait();
}
This will work but spin up another thread? At least it will not make the thread avail for the pool and the purpose of async here is gone.
Or is this supported B:
async void VoidDelegate(CacheEntryUpdateArguments arguments) {
await SomeApi.AsyncOnlyMethodAsync();
}
But this is a fire-and-forget - but cache update event needs to fetch the new data before returning result. Same goes for e.g. button command event - page could be completed before the command has finished.
You can mark any method that returns void, Task, or Task<T> as async. Marking a method as async doesn't change the signature of the method, so you're allowed to simply mark VoidDelegate as async if you want it to await things.
Note that, since you now have an async void method, this will be a fire-and-forget method. When someone invokes the delegate the method will return very quickly, while the asynchronous work continues to happen, and the caller will have no way of knowing when the work finishes, or if it errors.
Related
I'm trying to wait for an asynchronous function to complete so that I can populate a ListView in my UI thread.
Here's the code
public Form1()
{
InitializeComponent();
Task t = new Task(Repopulate);
t.Start();
// some other work here
t.Wait(); //completes prematurely
}
async void Repopulate()
{
var query = ParseObject.GetQuery("Offer");
IEnumerable<ParseObject> results = await query.FindAsync();
if (TitleList == null)
TitleList = new List<string>();
foreach (ParseObject po in results)
TitleList.Add(po.Get<string>("title"));
}
TitleList = null in Form1() because Repopulate() hasn't been completed yet. Therefore I used Wait(). However, wait returns before function is even completed.
What am I doing wrong here?
You need to change the return type of your Repopulate method to return a task representing the asynchronous operation.
Also, you shouldn't perform asynchronous operations from your form constructor, since calling Task.Wait will cause your UI thread to block (and your application to appear unresponsive). Rather, subscribe to its Form.Load method, and perform the asynchronous operations there, using the await keyword to keep the event handler asynchronous. If you don't want the user to interact with the form until the asynchronous operation completes, then disable the form within the constructor and re-enable it at the end of the Load handler.
private async void Form1_Load(object sender, EventArgs e)
{
Task t = Repopulate();
// If you want to run its synchronous part on the thread pool:
// Task t = Task.Run(() => Repopulate());
// some other work here
await t;
}
async Task Repopulate()
{
var query = ParseObject.GetQuery("Offer");
IEnumerable<ParseObject> results = await query.FindAsync();
if (TitleList == null)
TitleList = new List<string>();
foreach (ParseObject po in results)
TitleList.Add(po.Get<string>("title"));
}
Update: For the benefit of future readers, I'm reworking my comments into the answer:
Task.Wait causes the calling thread to block until the task completes. Form constructors and event handlers, by their nature, run on the UI thread, so calling Wait within them will cause the UI thread to block. The await keyword, on the other hand, will cause the current method to relinquish control back to the caller – in the case of event handlers, this would allow the UI thread to continue processing events. The awaiting method (event handler) would then resume execution on the UI thread after the task completes.
Task.Wait will always block the calling thread, whether it's called from the constructor or the event handler, so one should avoid using it, especially when running on the UI thread. C# 5 introduced the async and await keywords to this end; however, they're only supported on methods, not constructors. This restriction underlies the main reason why you need to move your initialization code from the form constructor to an async event handler.
As to the reason why Task.Wait() returns prematurely: In your original code, task t represents the execution of the Task that you instantiated in your form constructor. This task runs Repopulate; however, the said method will return as soon as it encounters the first await statement, and execute the rest of its logic in a fire-and-forget fashion. This is the danger of using async void – you won't know when the asynchronous method has completed executing. (For this reason, async void should only be used for event handlers.) In other words, t.Wait() returns as soon as Repopulate hits its first await.
By changing the signature of Repopulate to async Task, you are now getting another task that represents the completion of its asynchronous execution, including the query.FindAsync() asynchronous call and the processing that succeeds it. When Task.Run is passed an asynchronous operation (Func<Task>) as argument, its returned task will wait for (unwrap) the inner task. This is why Task.Run should be used instead of Task.Start or Task.Factory.StartNew.
I have a WPF application where I press a button and the following code executes:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
new Thread(
async () =>
{
Action lambda = async () =>
{
await Task.Delay(5000);
MessageBox.Show("Lambda done");
};
await this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, lambda).Task;
MessageBox.Show("Dispatch done");
}).Start();
}
MSDN documentation of DispatcherOperation.Task says : Gets a Task<TResult> that represents the current operation. (It's not a Task<TResult> tho :/)
So I thought awaiting this would mean that the MessageBox.Show("Dispatch done"); will only be executed after the lambda is finished. However, it is not the case. The MessageBox with "Dispatch done" text is shown as soon as the button is pressed, and the one with "Lambda done" text is shown 5 seconds after, as expected.
Can someone explicate this? I don't understand why it is happening.
This line:
Action lambda = async ...
is creating an async void lambda rather than an async Task lambda. One of the (many) problems with async void is that there is no (easy) way to tell when it completes. For this reason, "avoid async void" is one of the best practices in my MSDN article on the subject.
I haven't tried it, but I suspect that Dispatcher.BeginInvoke can only take Action delegates (and not the more async-friendly Func<Task>), in which case it may be better to use Dispatcher.Invoke and pass a Func<Task>. In my own code, though, I avoid Dispatcher entirely; I find it encourages worse code. Instead of Dispatcher, consider using await and/or Progress<T>.
I have a program which has no purpose but to help me understand how async and await works. It's a console application which parses XML and waits for a name to be returned, either the surname or the first name. Here is the code:
static void Main(string[] args)
{
Task<string> name = GetFirstParsedName();
name.Wait();
if (name.IsCompleted)
{
Console.WriteLine(name.Result);
}
Console.ReadLine();
}
static async Task<string> GetFirstParsedName()
{
string xmlSnippet = #"<person>
<FirstName>Chamir</FirstName>
<Surname>Bodasing</Surname>
<Gender>Male</Gender>
<Nationality>South African</Nationality></person>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlSnippet);
XmlParser xmlParser = new XmlParser();
Task<string> t_GetFirstName = xmlParser.GetFirstName(xmlDoc);
Task<string> t_GetSurname = xmlParser.GetSurname(xmlDoc);
Task<string> t_firstReturnedName = await Task.WhenAny(new Task<string>[] { t_GetFirstName, t_GetSurname });
string firstReturnedName = await t_firstReturnedName;
return firstReturnedName;
}
static async Task<string> GetFirstName(XmlDocument personXml)
{
string firstName = personXml.SelectSingleNode("//FirstName").InnerText;
await Task.Delay(5000);
return firstName;
}
static async Task<string> GetSurname(XmlDocument personXml)
{
string surname = personXml.SelectSingleNode("//Surname").InnerText;
await Task.Delay(1);
return surname;
}
It seems like it only makes sense to use the async method when you don't have to return a value to a main method. Unless it means setting a global class property which can then be accessed. If not, in order to await the method, all methods need to be async which in turn means that the return type must be Task<T>. It seems like it never ends unless I explicitly have to write the following code (as in above main method):
Task<string> name = GetFirstParsedName();
name.Wait();
if (name.IsCompleted)
{
Console.WriteLine(name.Result);
}
Is my understanding correct at all? I have to use the result property to get the value here and from reading up about this, it seems that this is not the best practice.
It seems like it only makes sense to use the async method when you don't have to return a value to a main method. Unless it means setting a global class property which can then be accessed.
Your async methods can return Task<T> to return a value to its caller. Asynchronous methods do not work very well if they depend on side effects (i.e., setting properties / globals); they work much better if your code is more pure (i.e., taking parameters and returning results).
If not, in order to await the method, all methods need to be async which in turn means that the return type must be "Task" . It seems like it never ends
This is why one of the central principles of async is "async all the way". In most applications, this is exactly what you should do. Eventually, the "async chain" generally ends in an async void event handler (for UI apps) or an async Task<T> entry point (for ASP.NET apps). Console apps are unusual since they do require an explicit Wait()/Result or equivalent in their Main method.
After all, the whole point of async is to free up the calling thread. If the next method up the call stack blocks that same thread until the async code is complete, well, that was a whole lot of work for no benefit...
It seems like it only makes sense to use the async method when you don't have to return a value to a main method.
Why do you say that? It makes sense to use an async method where-ever you have a naturally asynchronous operation ongoing. No matter if that operation has a return value or doesn't.
in order to await the method, all methods need to be async which in turn means that the return type must be "Task" . It seems like it never ends
That's correct. Async spreads in your code like a plage, from the bottom to the top of your stack. It usually reaches the highest calling place in your stack (be it a console Main method or a UI event handler). That's the advantage of using async, it allows you to asynchronously wait an operation while freeing the calling thread. This can help, for example, if you have a WebAPI endpoint which needs to handle a large amount of requests concurrently. If you spend most of your time querying a database, you can free that calling thread in the meanwhile to serve more requests.
Is my understanding correct at all? I have to use the result property to get the value here and from reading up about this, it seems that this is not the best practice.
You have to use the Result property because a console application is a special case, where Main cant be marked as async (unless you're using ASP.NET CoreCLR console app). If this was a UI event handler or an ASP.NET action, you'd properly await the async call.
Well, async keyword let's compiler know that your method is going to execute series of asynchronous calls that should most likely be awaited but should not block the main (or UI) thread.
To help you understand async-await a little bit, here is some simple example:
Consider the scenario, when user clicks 'Save' button on WinForm's app, and some UI operation is started asynchronously in different Thread.
The code is :
private Task SomeUIOperation()
{
// ui operation
return Task.Run(() =>
{
this.Invoke(new Action(() => this.BackColor = Color.Aquamarine));
Thread.Sleep(10000);
this.Invoke(new Action(() => this.BackColor = Color.Gray));
});
}
private async void button1_Click(object sender, EventArgs e)
{
await SomeUIOperation();
// some other stuff
}
If we do not use async-await here UI thread will become unresponsive for 10 seconds.
It's an example of how you usually use async-await, you use it when you want some piece of code to be executed only when asynchronous operation is completed and in the same time you do not want the main thread to be blocked.
And console application is not the best project type for testing and learning Async-Await
I have a method in my view model
private async void SyncData(SyncMessage syncMessage)
{
if (syncMessage.State == SyncState.SyncContacts)
{
this.SyncContacts();
}
}
private async Task SyncContacts()
{
foreach(var contact in this.AllContacts)
{
// do synchronous data analysis
}
// ...
// AddContacts is an async method
CloudInstance.AddContacts(contactsToUpload);
}
When I call SyncData from the UI commands and I'm syncing a large chunk of data UI freezes. But when I call SyncContacts with this approach
private void SyncData(SyncMessage syncMessage)
{
if (syncMessage.State == SyncState.SyncContacts)
{
Task.Run(() => this.SyncContacts());
}
}
Everything is fine. Should not they be the same?
I was thinking that not using await for calling an async method creates a new thread.
Should not they be the same? I was thinking that not using await for
calling an async method creates a new thread.
No, async does not magically allocate a new thread for it's method invocation. async-await is mainly about taking advantage of naturally asynchronous APIs, such as a network call to a database or a remote web-service.
When you use Task.Run, you explicitly use a thread-pool thread to execute your delegate. If you mark a method with the async keyword, but don't await anything internally, it will execute synchronously.
I'm not sure what your SyncContacts() method actually does (since you haven't provided it's implementation), but marking it async by itself will gain you nothing.
Edit:
Now that you've added the implementation, i see two things:
I'm not sure how CPU intensive is your synchronous data analysis, but it may be enough for the UI to get unresponsive.
You're not awaiting your asynchronous operation. It needs to look like this:
private async Task SyncDataAsync(SyncMessage syncMessage)
{
if (syncMessage.State == SyncState.SyncContacts)
{
await this.SyncContactsAsync();
}
}
private Task SyncContactsAsync()
{
foreach(var contact in this.AllContacts)
{
// do synchronous data analysis
}
// ...
// AddContacts is an async method
return CloudInstance.AddContactsAsync(contactsToUpload);
}
What your line Task.Run(() => this.SyncContacts()); really does is creating a new task starting it and returning it to the caller (which is not used for any further purposes in your case). That's the reason why it will do its work in the background and the UI will keep working. If you need to (a)wait for the task to complete, you could use await Task.Run(() => this.SyncContacts());. If you just want to ensure that SyncContacts has finished when you return your SyncData method, you could using the returning task and awaiting it at the end of your SyncData method. As it has been suggested in the comments: If you're not interested in whether the task has finished or not you just can return it.
However, Microsoft recommend to don't mix blocking code and async code and that async methods end with Async (https://msdn.microsoft.com/en-us/magazine/jj991977.aspx). Therefore, you should consider renaming your methods and don't mark methods with async, when you don't use the await keyword.
Just to clarify why the UI freezes - the work done in the tight foreach loop is likely CPU-bound and will block the original caller's thread until the loop completes.
So, irrespective of whether the Task returned from SyncContacts is awaited or not, the CPU bound work prior to calling AddContactsAsync will still occur synchronously on, and block, the caller's thread.
private Task SyncContacts()
{
foreach(var contact in this.AllContacts)
{
// ** CPU intensive work here.
}
// Will return immediately with a Task which will complete asynchronously
return CloudInstance.AddContactsAsync(contactsToUpload);
}
(Re : No why async / return await on SyncContacts- see Yuval's point - making the method async and awaiting the result would have been wasteful in this instance)
For a WPF project, it should be OK to use Task.Run to do the CPU bound work off the calling thread (but not so for MVC or WebAPI Asp.Net projects).
Also, assuming the contactsToUpload mapping work is thread-safe, and that your app has full usage of the user's resources, you could also consider parallelizing the mapping to reduce overall execution time:
var contactsToUpload = this.AllContacts
.AsParallel()
.Select(contact => MapToUploadContact(contact));
// or simpler, .Select(MapToUploadContact);
I had a situation recently where I had an ASP.NET WebAPI controller that needed to perform two web requests to another REST service inside its action method. I had written my code to have functionality separated cleanly into separate methods, which looked a little like this example:
public class FooController : ApiController
{
public IHttpActionResult Post(string value)
{
var results = PerformWebRequests();
// Do something else here...
}
private IEnumerable<string> PerformWebRequests()
{
var result1 = PerformWebRequest("service1/api/foo");
var result = PerformWebRequest("service2/api/foo");
return new string[] { result1, result2 };
}
private string PerformWebRequest(string api)
{
using (HttpClient client = new HttpClient())
{
// Call other web API and return value here...
}
}
}
Because I was using HttpClient all web requests had to be async. I've never used async/await before so I started naively adding in the keywords. First I added the async keyword to the PerformWebRequest(string api) method but then the caller complained that the PerformWebRequests() method has to be async too in order to use await. So I made that async but now the caller of that method must be async too, and so on.
What I want to know is how far down the rabbit hole must everything be marked async to just work? Surely there would come a point where something has to run synchronously, in which case how is that handled safely? I've already read that calling Task.Result is a bad idea because it could cause deadlocks.
What I want to know is how far down the rabbit hole must everything be
marked async to just work? Surely there would come a point where
something has to run synchronously
No, there shouldn't be a point where anything runs synchronously, and that is what async is all about. The phrase "async all the way" actually means all the way up the call stack.
When you process a message asynchronously, you're letting your message loop process requests while your truly asynchronous method runs, because when you go deep down the rabit hole, There is no Thread.
For example, when you have an async button click event handler:
private async void Button_Click(object sender, RoutedEventArgs e)
{
await DoWorkAsync();
// Do more stuff here
}
private Task DoWorkAsync()
{
return Task.Delay(2000); // Fake work.
}
When the button is clicked, runs synchronously until hitting the first await. Once hit, the method will yield control back to the caller, which means the button event handler will free the UI thread, which will free the message loop to process more requests in the meanwhile.
The same goes for your use of HttpClient. For example, when you have:
public async Task<IHttpActionResult> Post(string value)
{
var results = await PerformWebRequests();
// Do something else here...
}
private async Task<IEnumerable<string>> PerformWebRequests()
{
var result1 = await PerformWebRequestAsync("service1/api/foo");
var result = await PerformWebRequestAsync("service2/api/foo");
return new string[] { result1, result2 };
}
private async string PerformWebRequestAsync(string api)
{
using (HttpClient client = new HttpClient())
{
await client.GetAsync(api);
}
// More work..
}
See how the async keyword went up all the way to the main method processing the POST request. That way, while the async http request is handled by the network device driver, your thread returns to the ASP.NET ThreadPool and is free to process more requests in the meanwhile.
A Console Application is a special case, since when the Main method terminates, unless you spin a new foreground thread, the app will terminate. There, you have to make sure that if the only call is an async call, you'll have to explicitly use Task.Wait or Task.Result. But in that case the default SynchronizationContext is the ThreadPoolSynchronizationContext, where there isn't a chance to cause a deadlock.
To conclude, async methods shouldn't be processed synchronously at the top of the stack, unless there is an exotic use case (such as a Console App), they should flow asynchronously all the way allowing the thread to be freed when possible.
You need to "async all the way up" to the very top of the call stack, where you reach a message loop that can process all of the asynchronous requests.