Best way to convert callback-based async method to awaitable task - c#

What would be the best way to convert/wrap a "classic" asynchronous method that uses a callback to something that returns a (awaitable) Task?
For example, given the following method:
public void GetStringFromUrl(string url, Action<string> onCompleted);
The only way I know of to wrap this into a method returning a task is:
public Task<string> GetStringFromUrl(string url)
{
var t = new TaskCompletionSource<string>();
GetStringFromUrl(url, s => t.TrySetResult(s));
return t.Task;
}
Is this the only way to accomplish this?
And is there a way to wrap the call to GetStringFromUrl(url,callback) in the task itself (i.e. the call itself would run inside the task instead of synchronously)

Your code is short, readable and efficient, so I don't understand why are you looking for alternatives, but I can't think of anything. I think your approach is reasonable.
I'm also not sure why do you think that the synchronous part is okay in the original version, but you want to avoid it in the Task-based one. If you think the synchronous part might take too long, fix it for both versions of the method.
But if you want to run it asynchronously (i.e. on the ThreadPool) only in the Task version, you can use Task.Run():
public Task<string> GetStringFromUrl(string url)
{
return Task.Run(() =>
{
var t = new TaskCompletionSource<string>();
GetStringFromUrl(url, s => t.TrySetResult(s));
return t.Task;
});
}

Your assumed implementation is perfectly fine for this assuming the callback only ever handles successful situations. What currently happens if an exception happens within the async underpinnings of the GetStringFromUrl implementation? There's no real way for them to propagate that to the Action callback... do they just swallow it and return you null or something?
The only thing I would recommend is using following the new convention of naming such async methods with the XXXAsync suffix.

Related

Blazor invoke JS from synchronous method

I have a piece of code in an Action that is querying a JS funtion.
Unfortunately I didn't make my registered action async at first and realized that the following code was stuck at the InvokeAsync line
async Task someCode() {
string myRes = await jsRuntime.InvokeAsync<string>("MyMethod");
Console.WriteLine(myCode); // <- this line was not reached!
}
public void myAction() {
// synchronous here => how to convert it to synchronous code?!
someCode.GetAwaiter().Result();
}
Because of this, the WriteLine part of code was not reached... Is there a proper way to call the async method here from the synchrounous method? Can anyone clarify why the following code works :
public async Task myAction() {
await someCode;
}
I think that you have a sort of deadlock, change myAction:
public void myAction() {
var result = someCode.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
}
Could be because InvokeAsync returns a ValueTask type. You cannot get the result of a ValueTask. You have to convert it to a Task to read the result synchronously.
Check the remarks of the ValueTask docs. Specifically the bullet points:
The following operations should never be performed on a ValueTask<TResult> instance
Awaiting the instance multiple times.
Calling AsTask multiple times.
Using .Result or .GetAwaiter().GetResult() when the operation hasn't yet completed, or using them multiple times.
Using more than one of these techniques to consume the instance.
I know you are calling .GetResult() on a Task returned by someCode(), but I'm guessing it's not behaving the way you want because you're indirectly trying to get the result of a ValueTask. Two possible options would be:
Use Invoke instead of InvokeAsync. This is only available for Blazor WASM apps. See docs.
Cast the ValueTask to a Task to get result properly. For example, string myRes = await jsRuntime.InvokeAsync<string>("MyMethod").AsTask();.

Is it just plain wrong to return Task instead of Task<T>?

The task API feels sort of like a pit of failure, given how every possible thing I could do with it comes with more DON'T than DO. But I'm trying to use it more, and I'm confused about the entire issue of async void.
My problem happens in a place where my application's used a local data file forever, and because it was fast synchronous calls were used. Now some remote sources are an option, and they have enough latency I'm switching it all to be asynchronous.
So I've got a method that maybe looks like this:
void InitializeData() {
SomeProperty = _dataSource.Load(...);
}
The naive thing I want to do for low-friction is:
Task InitializeDataAsync() {
return Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
But there are SO many articles about how terrible it is to use async void, and they seem to blur with discussion of returning a Task. So is my best option really to write it like:
Task<DataType> FetchDataAsync() {
return _dataSource.LoadAsync(...);
}
...then hunt down all the callers and make them comply?
I feel like the argument people make is that async void is bad because of the different behavior of async Task and the dreaded UnobservedTaskException when you use await. In this situation, I'm very unlikely to ever be using await. Or if I do use await, it's always going to have a try/catch around it because we're already paranoid about UnobservedTaskException.
So:
Is "Don't use async void" the same thing as "Don't use Task?
If you don't use await, does it mitigate that?
If you do use await, does always wrapping it with a try/catch mitigate the issue?
async void is not the same as returning a Task. The problem with async void is there is no way to observe task exceptions (other then the global exception handler), and no way to wait for the task to complete (you actually can't await an async void method because there is nothing to await), this is why it should be avoided.
Returning Task does not have these problems, if you await it you know when it completes and you will get exceptions where you await so returning a Task is perfectly acceptable.
It looks like you're just confused. The await/async API is incredibly simple. The only confusing part is understanding the difference between await/async API and the Task API. I won't go into great detail about this as the Stephen Cleary's blog clearly covers this, but here is the important excerpt:
To reiterate a sentence from my last post, use Task.Run to call CPU-bound methods (from GUI threads). Do not use it just to “provide something awaitable for my async method to use”.
next...
The naive thing I want to do for low-friction is:
Task InitializeDataAsync() {
return Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
This is a clear case of offloading Sync code into a Async wrapper which doesn't really do any good.
But there are SO many articles about how terrible it is to use async void,
This is clearly not a async void method. This is a non-async Task returning method. Here is an async void method:
async void InitializeDataAsync() {
await Task.Run(() => {
SomeProperty = _dataSource.Load(...);
});
}
they seem to blur with discussion of returning a Task.
I've not read anything that blurs this information. It's pretty simple; if you have an async method, always return Task or Task<T> (except as stated below). The difference between using these two (Task or Task<T>) is purely design/architecture.
So is my best option really to write it like:
Best is really an opinion here. Both of these work and don't forget async/wait
async Task<DataType> FetchDataAsync() {
return await _dataSource.LoadAsync(...);
}
async Task FetchDataAsync() {
_data = await _dataSource.LoadAsync(...);
}
I feel like the argument people make is that async void is bad because of the different behavior of async Task and the dreaded UnobservedTaskException when you use await.
The most important difference is how exceptions are handled:
Excerpt:
Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async Task method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the SynchronizationContext that was active when the async void method started.
So
Or if I do use await, it's always going to have a try/catch around it because we're already paranoid about UnobservedTaskException.
This means that you can't catch an exception by try/catch around async void. That is a huge problem!
Is "Don't use async void" the same thing as "Don't use Task?"
Well this is apples and oranges. Yes: don't use async void unless you're using them for async event handlers.
Don't use Task's unless they are CPU bound or you're using a Framework call (or you've correctly wrapped your own method which uses IO Completion Ports).
If you don't use await, does it mitigate that?
Hopefully by now you understand that await/async is different from a Task, and what you're trying to do is write all await/async code.
If you do use await, does always wrapping it with a try/catch mitigate the issue?
Depends, as stated above.

Where does async and await end? Confusion

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

What is the correct way to call an async method from synchronous code, and block until the task is complete? [duplicate]

This question already has answers here:
How Do I Call an Async Method from a Non-Async Method? [duplicate]
(2 answers)
How to call asynchronous method from synchronous method in C#?
(17 answers)
Closed 6 years ago.
Consider this code:
public async Task DoStuffAsync() {
await WhateverAsync(); // Stuff that might take a while
}
// Elsewhere in my project...
public async Task MyMethodAsync() {
await DoStuffAsync();
}
public void MyMethod() {
DoStuffAsync(); // <-- I want this to block until Whatever() is complete.
}
I want to provide two methods with the same functionality: an async method which runs asynchronously, and a non-async method that blocks, and either of these two methods can be called depending on whether the code I'm calling from is also async.
I don't want to repeat loads of code everywhere and create two versions of each method, wasting time and effort and reducing maintanability.
I'm guessing I can do something like one of the following:
// Call it just like any other method...
// the return type would be Task though which isn't right.
DoStuffAsync();
// Wrap it in a Task.Run(...) call, this seems ok, but
// but is doesn't block, and Task.Run(...) itself returns an
// awaitable Task... back to square one.
Task.Run(() => DoStuffAsync());
// Looks like it might work, but what if I want to return a value?
DoStuffAsync().Wait();
What is the correct way to do this?
UPDATE
Thanks for your answers. The general advice seems to be just provide an Async method and let the consumer decide, rather than creating a wrapper method.
However, let me try to explain my real-world problem...
I have a UnitOfWork class that wraps the the SaveChanges() and SaveChangesAsync() methods of an EF6 DbContext. I also have a List<MailMessage> of emails that need to be sent only when the SaveChanges() succeeds. So my code looks like this:
private readonly IDbContext _ctx;
private readonly IEmailService _email;
private readonly List<MailMessage> _emailQueue;
// ....other stuff
public void Save() {
try {
_ctx.SaveChanges();
foreach (var email in _emailQueue) _email.SendAsync(email).Wait();
} catch {
throw;
}
}
public async Task SaveAsync() {
try {
await _ctx.SaveChangesAsync();
foreach (var email in _emailQueue) await _email.SendAsync(email);
} catch {
throw;
}
}
So you can see that because an EF6 DbContext provides an async and non-async version, I kinda have to as well... Based on the answers so far, I've added .Wait() to my SendAsync(email) method, which asynchronously sends out an email via SMTP.
So... all good, apart from the deadlock problem... how do I avoid a deadlock?
What is the correct way to do this?
The correct way would be to do what you don't want to do, expose two different methods, one which is completely synchronous and another which is completely asynchronous.
Exposing async over sync and sync over async are poth anti-patterns when dealing with async code.
If the methods aren't aren't naturally async, i would expose a synchronous version only and let the invoker decide if he wants to wrap it with a Task.Run himself.
If the method is naturally async, i would expose the async method only. If you have both sync and async versions, expose them independently.
Async methods go "all the way", and they slowly bubble up and down the call stack as you use them. Embrace that fact, and you'll avoid many pitfalls along the way.
There is a Github project for that : AsyncBridge
Example included in the project homepage :
public async Task<string> AsyncString()
{
await Task.Delay(1000);
return "TestAsync";
}
public void Test()
{
string string1 = "";
string string2 = "";
using (var A = AsyncHelper.Wait)
{
A.Run(AsyncString(), res => string1 = res);
A.Run(AsyncString(), res => string2 = res);
}
}
I used it on several project without issue.
How do I do a blocking wait.
// Looks like it might work, but what if I want to return a value?
DoStuffAsync().Wait();
And it does. Regarding the
what if I want to return a value?
Suppose you also had this async method that returned a Task<string>:
public async Task<string> MyStringGetterAsync() {
return await GetStringAsync();
}
You could to the following to perform a blocking wait and retrieve its result:
var myString = MyStringGetterAsync().Result;
With regards to your intention:
I want to provide two methods with the same functionality: an async
method which runs asynchronously, and a non-async method that blocks,
and either of these two methods can be called depending on whether the
code I'm calling from is also async.
Creating a MyWhatEver() overload that just does MyWhatEverAsync.Wait() is not a recommended pattern, because it may have unintended side effects for clients calling that method, as explained e.g. here. The client calling your synchronous version of the method, might not expect its thread to be blocked as the result of calling your method, and cannot decide for itself if that is acceptable (e.g. it cannot specify ConfigureAwait). As mentioned by #Default in the comments, this could lead to deadlocks.
The same is generally true for the reverse case: i.e. having a MyWhatEverAsync() that only does return Task.Run(() => MyWhatEver()); If a client needs to, they could do this themselves and include e.g. a cancellation token, so they can control the task.
It is better to be explicit in your interface and only provide methods that do what their signature says they do.
For your real world problem (after question edit):
I have a UnitOfWork class that wraps the the SaveChanges() and
SaveChangesAsync() methods of an EF6 DbContext. I also have a
List<MailMessage> of emails that need to be sent only when the
SaveChanges() succeeds.
And (from the comments)
The success of sending an email isn't critical.
Your current UnitOfWork design for the Save and SaveAsync methods is not correct, because it violates the atomicity promises it makes.
In the scenario where "SaveChanges" succeeds, but an exception occurs on sending one of the emails. The client code calling one of the Save variants, will observe that exception, will (and should) assume that saving the changes failed, and could retry applying them.
If a client was wrapping this operation in a transaction context with a two phase commit, the "SaveChanges" would be rolled back, and when a client retries the operation, it will attempt to send the emails again, potentially causing a number of recipients to receive the email multiple times, although the changes they received the email about were not committed successfully (and may never be if sending emails fails repeatedly).
So you will need to change something.
If you really don't care about the success of sending the emails, I suggest you add the following method.
private Task SendEmailsAndIgnoreErrors(IEmailService emailService, List<MailMessage> emailQueue) {
return Task.WhenAll(emailQueue.Select(async (m) => {
try {
await emailService.SendAsync(m).ConfigureAwait(false);
} catch {
// You may want to log the failure though,
// or do something if they all/continuously fail.
}
}));
}
And use it like this:
public async Task SaveAsync() {
await _ctx.SaveChangesAsync();
await SendEmailsAndIgnoreErrors(_email, _emailQueue);
}
I would personally omit the synchronous variant, and let clients decide how to wait on the task, but if you believe you really need it, you could do this:
public void Save() {
_ctx.SaveChanges();
SendEmailsAndIgnoreErrors(_email, _emailQueue).Wait().ConfigureAwait(false);
}

Cleanest way of dealing with an IAsyncOperationWithProgress?

I've been using C# for quite a while, but somehow have not yet had the pleasure of using the whole await/async thing new in .Net 4. Well, now I'm making a console application that links to the WinRT libraries and WinRT is really.. well, asynchronous.
One thing I'm needing to do right now is install a package. So, I use PackageManager.AddPackageAsync This is of course asynchonous and returns an IAsyncOperationWithProgress
I know I could do something like
bool Done=false;
void Foo()
{
var tmp=new PackageManager.AddPackageAsync(...);
tmp.Completed= ... FooBar;
while(!Done){}
}
void FooBar(...)
{
Done=true;
}
But I'm pretty sure the whole async and await thing was designed for exactly this scenario. However, I don't understand how to use it in this context on an IAsyncOperationWithProgress
.Net includes a GetAwaiter() extension method that makes IAsyncOperationWithProgress awaitable.
You can just write await tmp; in an async method.
Your async method will return a Task (or Task<T>), which you can await from another async method, or call Wait() to synchronously block.
Async and Await allows you to program an Async operation as if it occurs on the calling thread. First you have to declare your operation as being async then you await the async operation from the other guy. Finally you do whatever work you wanted to do after that operation is complete.
async void Foo()
{
var tmp=await new PackageManager().AddPackageAsync(...);
//do something else;
}
Calling Foo will make it run in the background, but when AddPackageAsync completes, Foo rejoins the calling thread (e.g. the UI thread) to complete its work.
The other option is to call GetAwaiter extension method and call Wait() on it to manually block until the operation completes.
You can subscribe to that progress by using an overload of AsTask method, like the following
...= await new PackageManager().AddPackageAsync(...).AsTask(new Progress<DeploymentProgress>(...));

Categories

Resources