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();.
Related
I'm looking at the "good" example in this scenario, specifically assigning the result of an async method to a variable. (In this case it's a discard variable but it works the same if I just do var x =).
public void Heartbeat(object state)
{
// Discard the result
_ = DoAsyncPing();
}
private async Task DoAsyncPing()
{
await _client.GetAsync("http://mybackend/api/ping");
}
In trying this myself, I notice that if I remove the _ variable, I get compiler warnings saying "this call is not awaited". Why does assigning the result make a difference to how the method is called? Is there an implicit await somewhere?
With the _ keyword its assigning the output of DoAsyncPing() to _ as a Task. In that case there is no execution yet its just a task.
Without the _= then the function is called and the compiler is warning you that the call is not awaited. So the first method is assignment and the second is execution
About your code, _ contains Task.
If you don't put await execution of existing method will continue regardless of your async method's completion status
if you need to wait for some async operation to be completed before continuing the current method you should put await
let's take an example.
You want some counter data from a website you a method for that (E.g public async Task<int> GetCounter())
Here GetCounter is an async method but you should wait for it before continuing. hence put await.
You want to push +1 counter to the same website now you don't want to know if the website received that or not at that time you can ignore putting await.
If you want to invoke an Async method you will have to return Task instead of void.
Since you're trying to call DoAsyncPing() from Heartbeat:
1.- Convert void Heartbeat(object state) to async Task HeartbeatAsync(object state).
Adding the async statement will allow you to await inside it.
Convention says you might need to call awaitable/async methods
MethodNameAsync().
2.- Covering previous requirement, you now would be able to call DoAsyncPing() (I suggest renaming it to DoPingAsync() this way:
public async Task Heartbeat(object state)
{
// Discard the result
_ = await DoAsyncPing();
}
Give a try to this Stephen's Cleary post where explains how to work with async and await and why you should avoid async void. In a nutshell: just use async void on events and when you call an async method, everything inside it has to return at least Task.
Hope it helped.
My requirement is that I have to send a list of brokered messages to the azure service bus asynchronously. However I am not able to implement the SendBatchAsync method properly. Let me explain in detail. Here is my code:
public async Task SendBatchEnrollmentMessages()
{
while(somevalue)
{
//logic to fetch data from the SQL db through stored proc into list of brokered message i.e. messageList
if(messageList.Count() > 0)
{
await sender.SendMessagesAsync(messageList);
}
//some more logic for somevalue
}
}
where the SendMessageAsync logic is :
public async Task SendMessagesAsync(List<BrokeredMessage> brokeredMessageList)
{
var topicClient = CreateTopicClient();
await topicClient.SendBatchAsync(brokeredMessageList);
}
My issue is that when I debug the application using break point, the compiler comes till await topicClient.SendBatchAsync(brokeredMessageList); and exits the code i.e application debuggin is completed. It doesn't return back to the while condition. However instead of using SendBatchAsync if I use SendBatch, it works fine. What am I doing wrong?
Solution: The issue was with the test method which was calling the above funciton. It was of type void. It should have been of type async Task. A big thanks to Ned Stoyanov for helping me out in this.
An async method returns when after encounters an await statement and sets up the asynchronous operation being awaited. The rest of the method then continues after the await is finished.
You probably can't step through async methods like that, but try putting a breakpoint after the await and it should get hit when the asynchronous call completes.
Alternatively you may have a deadlock, see this post for some ways to avoid it.
As mentioned in our discussion the unit test needs to be async as well, return a Task and await any async calls
[TestMethod]
public async Task SendRegionsEnrollmentMessages()
{
EventManager eventMgr = new EventManager(clientUrn, programUrn, "CW");
await eventMgr.SendBatchEvents(EventType.ENROLLMENT);
}
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);
}
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>(...));
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.