How to call inter related async method within a web api method - c#

I have a web api method that needs to call 2 asynchronous method from another party, and the result of the first async method is required in order to call the second async method. I have something like the below code, which obviously doesn't work as with the await keyword, my understanding is it will go to the next line and continue and at the same time return a Task object to the caller.
A brief explanation of what I need from this method is that, I need to get a token from a third party async method, after that, base on the token, I need to do some stuff, then use the token to call another aysnc method from the third party again.
public async Task<ResponseObj> DoSomething()
{
var token = await GetTokenAsync();
DoStuff1();
var stuff = await CreateStuff(token);
SaveStuff(stuff);
ResponseObj response = new ResponseObj(stuff);
return response;
}
I've read a few article and example online and some people say instead of await, I can use Task.Result so that the next depending call won't run until the task return the result, some people use Task.Wait and seems like it will wait until the task finishes. I've tried both and failed to achieve my expected result, which CreateStuffAsync can't start until I have the result from GetTokenAsync.
Can someone point out what I've done wrong? Let's say if the first await already return a task to the caller, then what happen when the second await is reached? Am I supposed to not have more than 1 await in the method especially when one rely on the other one?

That code is right in the sense of it is waiting for the first async call, getting the result and then continuing with the second async call.

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();.

Call async method synchronously with await

I'm calling an async method (LoginAsync) for Authorization.
UserObject = clienAuthenticationService.LoginAsync(sUser).Result;
if (UserObject != null)
{
// Proceed for further code;
}
else
{
// Show Error message of failed authentication;
}
As this is third party service, I need output of LoginAsync before I go to next line (If block).
Current code is working fine for me and I know it waits until LoginAsync is executed.
However, I'm getting recommendation to Replace this use of 'Task.Result' with 'await'.
Question : I'm not sure if my case is relevant for await, since I need kind of Synchronous execution of async method. Can someone please confirm if recommendation given to me is irrelevant in my case or there is way to call async method synchronously with await ?
EDIT : After comments, I modified my code to add await instead of .Result. Still, unable to read response from async method. Below is new code
public static async Task<bool> CallJimService(LoginUserClass sUser)
{
var result = clientJIMServiceCall.LoginAsync(sUser).ConfigureAwait(false);
LoginUserClass loginUserDetails = await result;
if (loginUserDetails != null && loginUserDetails.UserProperties != null && loginUserDetails.UserProperties.LoggedIn)
{
return true;
}
else
{
return false;
}
}
public static Boolean ValidateUserCredentails(string pstrUserName, string pstrPassWord)
{
LoginUserClass sUser = new LoginUserClass();
sUser.UserName = pstrUserName;
sUser.Password = pstrPassWord;
return CallJimService(sUser).Result; // Here I want to avoid using .Result.
}
Also, I don't want to change ValidateUserCredentails() to async. How Can I get through this?
The LoginAsync method is marked async, and returns a Task. This method is expected to have an asynchronous implementation. You cannot execute this method synchronously, because this method does not have a synchronous implementation. If the class you are using would provide a synchronous implementation of the Login operation, they would have to expose a Login method.
There is no guarantee that calling this method asynchronously will result in an asynchronous operation. Asynchronous methods may return synchronously if the state needs them to. For instance, AsyncLogin may return synchronously if you already have logged in. However, unless doing something extremely specific, there must be at least one execution path in the method that requires some asynchronous operation.
Recommendation given to you is not irrelevant.
You should not block on an async operation, especially using Task.Result. Asynchronous operations does not involve multithreading, and awaiting on a Task.Result may provoke a deadlock of your application, because your thread will be waiting on the Result and will not be able to respond to the async operation signaling completion.
You'd rather await the LoginAsync method asynchronously, making your method async as well.
If you are forced to call the LoginAsync method from a synchronous context, the correct implementation will depend on what exactly you are trying to achieve and what the LoginAsync method does.
If you are able to use await (that is if you are in an async method already), then use await.
UserObject = await clienAuthenticationService.LoginAsync(sUser);
Using await helps the code run synchronous(that is it preserves flow of control).
I will try to explain async usage through the following example, which has asynchronous execution flow, but synchronous control flow -
Following code runs out of sync (asynchronous that is) -
// Authenticate the user, but don't wait here while authenticating.
// Async part could be - Checking database for user details. (Network IO operation)
var UserAuthTask = LoginAsync();
// Prepare a layout or something to show when authentication fails. Don't show yet.
// Again, don't wait while preparing.
// Async part could be - Reading a render template file. (File IO operation)
var AuthFailScreen = PrepareFailScreenAsync();
// Similar to failure screen.
var AuthSuccessScreen = PrepareSuccessScreenAsync();
Now, we use await to synchronize the flow to our liking -
var UserAuthResult = await UserAuthTask;
if (UserAuthResult.Success)
{
var SuccessScreen = await AuthSuccessScreen;
SuccessScreen.Show();
}
else
{
var FailScreen = await AuthFailScreen;
FailScreen.Show();
}
You could await each of the tasks before, like var UserAuthTask = await LoginAsync();, but then you would lose the benefit of doing multiple things which could've been done while authenticating.
I am not sure about exception handling, but mix and match of async and sync code will likely cause issues.
Please correct me if I am wrong at any point. Thanks.

ReadToEndAsync is blocking, how to get it to run asynchronously?

I call this getJson() function from an async action in my controller.
I have a list of large files that each take a few seconds for ReadToEndAsync() to process.
The ReadToEndAsync() is blocking even though I'm awaiting it.
How can I call ReadToEndAsync() asynchronously?
public static async Task<T> getJson<T>(String url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(server + url);
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
String jsonString;
//get the json string from the response
using (var xx = response.GetResponseStream())
{
StreamReader reader = new StreamReader(xx, Encoding.UTF8);
jsonString = await reader.ReadToEndAsync()
}
}
Controller:
_model.list.Add(await DataRetriever.getJson<ReviewModel>(url));
_model.list.Add(await DataRetriever.getJson<ReviewModel>(url));
_model.list.Add(await DataRetriever.getJson<ReviewModel>(url));
As noted in the comments, while the method ReadToEndAsync() does not block per se – in the usual sense of the word "block": that is, the thread that calls that method continues to run – it certainly will prevent the code after the await from executing until the method has completed. Which is exactly what you want: you don't want that code to execute until the read has completed, otherwise it wouldn't have the result to operate on.
You should probably (re?)read the documentation on async and await, but briefly: the keyword async is applied to a method to signal to the compiler that it will use await. The await is used to indicate to the compiler a point in the method where the compiler should save the current execution state of the method and return.
If and when the operation to which the await keyword has been applied completes, the framework will automatically continue execution of the method where it left off. Where the method is called in a thread that is tied to a synchronization context (e.g. a GUI thread in a Winforms or WPF program), by default this "continuation" is executed in that original thread (but this can be disabled when appropriate).
Please note above that the async method returns from await statements. Thus, the method itself does not block the thread, even as the operation represented by the method does "block" in some sense of the word.
So, with that all said, it seems to me that you may be trying to get your three operations to all complete asynchronously and concurrently. If you want to do that, you need to start all of the asynchronous operations at once, rather than waiting for each to complete before proceeding to the next as you do now (i.e. via the await statement applied to the call to the getJason<T>() method).
That would look something like this:
Task<ReviewModel> task1 = DataRetriever.getJson<ReviewModel>(url1),
task2 = DataRetriever.getJson<ReviewModel>(url2),
task3 = DataRetriever.getJson<ReviewModel>(url3);
_model.list.Add(await task1);
_model.list.Add(await task2);
_model.list.Add(await task3);
(Note: in your original code example, you only used a single url value. Since I assume you don't really want to just execute the same query three different times, I went ahead and changed the code example so that each task uses a different value).
In the above, even if the second and/or third task completes before the first, the results will be added to the result list in order. But the tasks themselves are started all at the same time so that they can run concurrently.
I hope that the above not only clarifies for you whether or not the call to the method ReadToEndAsync() is blocking (it does not, though because of the way the debugger presents the execution of your code, it might seem that it does), but also provides you with the solution to the larger problem that led you to debug the method and think that it's blocking. I.e. that your JSON queries didn't execute concurrently.
If between the comments on your question, and the above answer, you still have a problem, please edit your question so that it's more clear about what exactly you are asking.

How to do asynchronous web calls from within asp.net

Lets say im within an ASP.NET application, WCF or web API, part of this applications job to is contact a 3rd party over the way. Id like to do this asynchronously or rather non blocking so that the thread pool doesnt get starved. However i dont want to change all my code in the service only the bit that makes the web call.
Here is some code i have written:
public string GetSomeData()
{
Task<string> stuff = CallApiAsync();
return stuff.result; //does this block here?
}
private async Task<string> CallApiasync()
{
using (var httpClient = new HttpClient())
{
string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false);
return response;
}
}
I thought the idea was as follows but please correct any misconceptions.
The caller of CallApi can call the method and when it hits await there is a Task created which represents some work to be done asynchronously but that will take some time. At this point the thread reaches an await returns to the thread pool to do something else ie handle a different request. Once the Task completes the await line wakes up and the code continues from there as if it was synchronous.
If this is the case why do i need to return a Task from my apimethod. The caller seems to have to call stuff.Result which implies that the task may not have finished and calling result could block ? Note i don't want to make the calling method async too as then the method that calls that would need to be async etc etc.
What is the order of event here in my code?
One other question is why did i need to set configureAwait to false? otherwise everything hangs.
Id like to do this asynchronously or rather non blocking so that the thread pool doesnt get starved. However i dont want to change all my code in the service only the bit that makes the web call.
That's not possible. In order to be truly asynchronous, you must allow async to "grow" through the code as far as it needs to. What you're trying to do is block on an asynchronous call, which won't give you any benefit (you're freeing up a thread by using async, but then you're turning around and consuming a thread by using Result).
At this point the thread reaches an await returns to the thread pool to do something else ie handle a different request.
Not quite. When an async method hits an await, it returns an incomplete Task to its caller. If the caller, in turn, awaits that task, then it returns an incomplete Task to its caller, etc. When the ASP.NET runtime receives an incomplete Task from your action/service method/whatever, then it releases the thread to the thread pool.
So, you do have to go "async all the way" to see the real benefit of async.
I have an async intro on my blog if you want a more gentle introduction, as well as an MSDN article on async best practices (one of which is: async all the way). I also have a blog post that describes the deadlock you were seeing.
The compiler handles a lot of the magic behind the async pattern for you, but syntactically, you have to tell it what you want it to do by providing a method prototype that says "ok, this is an asynchronous operation that can be awaited."
For this to happen, your method must return a Task or Task<T>.
Any Task can be awaited.
You should be VERY careful when using .Result and .Wait(), as they can block in some very unexpected circumstances, because the runtime may decide to execute your method synchronously.
You should say:
await CallApiAsync();
or, to actually take advantage of it:
Task stuff = CallApiAsync();
//More code that can happen independetly of "stuff"
await stuff;
In order to do that, your GetSomeData() function must also be marked as async, but it doesn't have to, itself, return a Task.
Finished copy of a working async version of your code:
public async string GetSomeData()
{
Task stuff = CallApiAsync();
return await stuff;
}
private async Task<string> CallApiasync()
{
using (var httpClient = new HttpClient())
{
string response = await httpClient.GetStringAsync(Util.EndPoint).ConfigureAwait(false);
return response;
}
}
Honestly, if that's all the CallApiAsync function is ever going to do, you may as well inline it, though.

Async call with await in HttpClient never returns

I have a call I am making from inside a xaml-based, C# metro application on the Win8 CP; this call simply hits a web service and returns JSON data.
HttpMessageHandler handler = new HttpClientHandler();
HttpClient httpClient = new HttpClient(handler);
httpClient.BaseAddress = new Uri("http://192.168.1.101/api/");
var result = await httpClient.GetStreamAsync("weeklyplan");
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(WeeklyPlanData[]));
return (WeeklyPlanData[])ser.ReadObject(result);
It hangs at the await but the http call actually returns almost immediately (confirmed through fiddler); it is as if the await is ignored and it just hangs there.
Before you ask - YES - the Private Network capability is turned on.
Any ideas why this would hang?
Check out this answer to my question which seems to be very similar.
Something to try: call ConfigureAwait(false) on the Task returned by GetStreamAsync(). E.g.
var result = await httpClient.GetStreamAsync("weeklyplan")
.ConfigureAwait(continueOnCapturedContext:false);
Whether or not this is useful depends on how your code above is being called - in my case calling the async method using Task.GetAwaiter().GetResult() caused the code to hang.
This is because GetResult() blocks the current thread until the Task completes. When the task does complete it attempts to re-enter the thread context in which it was started but cannot because there is already a thread in that context, which is blocked by the call to GetResult()... deadlock!
This MSDN post goes into a bit of detail on how .NET synchronizes parallel threads - and the answer given to my own question gives some best practices.
Just a heads up - if you miss the await at the top level in an ASP.NET controller, and you return the task instead of the result as a response, it actually just hangs in the nested await call(s) with no errors. A silly mistake, but had I seen this post it might have saved me some time checking through the code for something odd.
Disclaimer: I don't like the ConfigureAwait() solution because I find it non-intuitive and hard to remember. Instead I came to the conclusion to wrap non awaited method calls in Task.Run(() => myAsyncMethodNotUsingAwait()). This seems to work 100% but might just be a race condition!? I'm not so sure what is going on to be honest. This conclusion might be wrong and I risk my StackOverflow points here to hopefully learn from the comments :-P. Please do read them!
I just had the problem as described and found more info here.
The statement is: "you can't call an asynchronous method"
await asyncmethod2()
from a method that blocks
myAsyncMethod().Result
In my case I couldn't change the calling method and it wasn't async. But I didn't actually care about the result. As I remember it also didn't work removing the .Result and have the await missing.
So I did this:
public void Configure()
{
var data = "my data";
Task.Run(() => NotifyApi(data));
}
private async Task NotifyApi(bool data)
{
var toSend = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
await client.PostAsync("http://...", data);
}
In my case I didn't care about the result in the calling non-async method but I guess that is quite common in this use case. You can use the result in the calling async method.

Categories

Resources