I am new to HttpClient. My code below always says "WaitingForActivation" in the status. Please help
private static async Task<HttpResponseMessage> MakeCall()
{
var httpclient = new HttpClient();
var response = await httpclient.GetAsync("http://localhost:60565/Subscribers");
return response;
}
Alternatively, if you environment is Synchronous add .Result, like so:
GetAsync("http://localhost:60565/Subscribers").Result;
That's normal. Just await the returned task to (asynchronously) wait for it to complete.
You may find my intro to async helpful.
As Cleary wrote in his post, in order to create an asynchronous call your task should be awaited too. That means, the method in your question (MakeCall()) is asynchronous but probably the call to the method is synchronous.
An asynchronous example class:
using System.Threading.Tasks;
public class SampleClass
{
public async Task<string> MakeCall()
{
# I am using the asynchronous call from the HttpClient library
var response = await client.PostAsJsonAsync(url, creds)
...
}
}
Try to await the call to the method.
var makeCall = await SampleClass.MakeCall();
What I would avoid is using .Result. As JDandChips already implies, it makes your call again synchronous. In this case, however, there is no need to try to make is asynchronous in the first place.
Related
In my C# app, I've been able to start concurrent tasks that make http calls and then wait for all of them to complete.
var responseTasks = new List<Task<HttpResponseMessage>>();
// PostChanges makes an async http call and returns the task
responseTasks.Add(myServiceClient.PostChanges(json));
responseTasks.Add(myServiceClient.PostChanges(json));
responseTasks.Add(myServiceClient.PostChanges(json));
Task.WaitAll(responseTasks.ToArray());
But what if each of the calls to PostChanges relies on a call that gets data from an http request? What is the simplest way to create a method that encapsulates the two calls and returns a started task? The method would have to make both requests something like this:
public Task<HttpResponseMessage> GetDataAndPostChanges(MyInput input)
{
var json = myServiceClient.GetData(input); // this call must complete first
var response = myServiceClient.PostChanges(json);
return response; // how to actually return a task immediately that does both calls?
}
I would then want to make concurrent calls to that method and wait for all of them to complete.
var responseTasks = new List<Task<HttpResponseMessage>>();
// PostChanges makes an async http call and returns the task
responseTasks.Add(myServiceClient.GetDataAndPostChanges(input1));
responseTasks.Add(myServiceClient.GetDataAndPostChanges(input2));
responseTasks.Add(myServiceClient.GetDataAndPostChanges(input3));
Task.WaitAll(responseTasks.ToArray());
Make the function async and await the necessary calls
public async Task<HttpResponseMessage> GetDataAndPostChanges(MyInput input) {
var json = await myServiceClient.GetData(input); // this call must complete first
var response = await myServiceClient.PostChanges(json);
return response;
}
The assumption above is that GetData is an asynchronous function.
Inside a MVC app, I have a Controller action that calls an async MethodA() which in turn calls an async MethodB(). MethodB() makes an awaitable call to another api.A calling method calls MethodA() with an await keyword. MethhodA() calls MethodB(), like this, MethodB().Result. This leads to a deadlock.
private async Task<bool> MethodA()
{
System.Diagnostics.Debug.WriteLine($"MethodA Start: {DateTime.UtcNow}");
var response = MethodB().Result;
System.Diagnostics.Debug.WriteLine($"MethodA End: {DateTime.UtcNow}");
return response;
}
public async Task<bool> MethodB()
{
System.Diagnostics.Debug.WriteLine($"MethodB start : {DateTime.UtcNow}");
using (var httpclient = new HttpClient())
{
var response = await httpclient.GetAsync(new Uri("http://localhost:62757/api/values"));
}
System.Diagnostics.Debug.WriteLine($"MethodB ending : {DateTime.UtcNow}");
return true;
}
This leads to a deadlock with an output:
MethodA Start: 04/08/2018 1:28:56
MethodB start : 04/08/2018 1:28:56
However, When I move the .Result out of MethodA() on to MethodB()'s call to the API, it does not cause a deadlock.
private async Task<bool> MethodA()
{
System.Diagnostics.Debug.WriteLine($"MethodA Start: {DateTime.UtcNow}");
var response = await MethodB();
System.Diagnostics.Debug.WriteLine($"MethodA End: {DateTime.UtcNow}");
return response;
}
public async Task<bool> MethodB()
{
System.Diagnostics.Debug.WriteLine($"MethodB start : {DateTime.UtcNow}");
using (var httpclient = new HttpClient())
{
var response = httpclient.GetAsync(new Uri("http://localhost:62757/api/values")).Result;
System.Diagnostics.Debug.WriteLine($"Response from 3rd party recieved : {DateTime.UtcNow}");
}
System.Diagnostics.Debug.WriteLine($"MethodB ending : {DateTime.UtcNow}");
return true;
}
This logic executes without a deadlock with output
MethodA Start: 04/08/2018 1:38:05
MethodB start : 04/08/2018 1:38:05
Response from 3rd party received : 04/08/2018 1:38:07
MethodB ending : 04/08/2018 1:38:07
MethodA End: 04/08/2018 1:38:07
I am struggling to understand the difference of these 2 scenarios. Why does .Result on an external api call not cause a deadlock, however an internal call with .Result cause a deadlock. Greatly appreciate help in understanding this behavior. Thanks in advance.
NOTE: It is recommended to use async/await all the way to the top. I am aware of this. The goal of this implementation was to understand the behavior of .Result thoroughly.
Practically, when we use await into async method its work as a thread. Sometimes we need to waiting for a result to another process run or we use async method into non async method. That time we use .Result. But another way to confiure await into async method that is set to ConfigureAwait false.
Like as
var response = await MethodB().ConfigureAwait(false);
I was reading the following topic http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
and decided to write a common utility method in my library to do a GET on remote url via HTTPClient
public static async Task<T> GetAsync<T>(HttpGetObject getObject)
{
string baseUrl = getObject.BaseUrl;
string actionUrl = getObject.ActionRelativeUrl;
string acceptType = getObject.AcceptType;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptType));
AddCustomHeadersToHttpClient(client, getObject);
// HTTP GET
HttpResponseMessage httpResponseMessage = await client.GetAsync(actionUrl).ConfigureAwait(false);
if (httpResponseMessage.IsSuccessStatusCode)
{
T response = await httpResponseMessage.Content.ReadAsAsync<T>().ConfigureAwait(false);
return response;
}
else
{
string message = httpResponseMessage.Content.ReadAsStringAsync().Result;
throw new Exception(message);
}
}
return default(T);
}
I know the "await httpResponseMessage.Content.ReadAsAsync().ConfigureAwait(false)" will prevent the deadlock in the above code
First:
My query is for "string message = httpResponseMessage.Content.ReadAsStringAsync().Result" line, will .Result can cause deadlock or not in that line?
Second:
If I call that code from UI like this:
public static object DoGet()
{
// Build getObject
var task = Utility.GetAsync(getObject);
task.Wait();
var response = task.Result;
return response;
}
Will that cause a deadlock?
Please note that I know to avoid all the mess with async-await, all the methods from UI to DAL must be async-await but I am not in position at this moment to change all that structure, my goal at this moment is to call HttpClient library and do a few GET operations.
So my questions is that will the above code can cause a deadlock?
Third:
Is task.Wait(); even needed in the above code?
In the general case, you should assume that yes, calling .Result or .Wait() on anything awaitable is dangerous and can deadlock (unless you are the library issuing the task, and you understand the full context). It is possible that it will work OK in some specific cases, but you should not rely on that behaviour, even if it works today.
I have a Web API service that is used to retrieve and update a specific set of data (MyDataSet objects), and I am running into some confusion in using async/await when performing the following events:
Update MyDataSet with new values
Get MyDataSet (but only after the new values have been updated)
In my client, I have something similar to the following:
Harmony.cs
private async Task<string> GetDataSet(string request)
{
using(var httpClient = new HttpClient())
{
httpClient.baseAddress = theBaseAddress;
HttpResponseMessage response = await httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return response.Content.ReadAsStringAsync().Result;
}
}
private async Task PostDataSet<T>(string request, T data)
{
using (var httpClient = new HttpClient())
{
client.BaseAddress = new Uri(theBaseAddress);
HttpResponseMessage response = await client.PostAsJsonAsync<T>(request, data);
response.EnsureSuccessStatusCode();
}
}
internal MyDataSet GetMyDataSetById(int id)
{
string request = String.Format("api/MyDataSet/GetById/{0}", id);
return JsonConvert.DeserializeObject<MyDataSet>(GetDataSet(request).Result);
}
internal void UpdateDataSet(MyDataSet data)
{
PostDataSet("api/MyDataSet/Update", data);
}
HarmonyScheduler.cs
internal void ScheduleDataSet()
{
MyDataSet data = ...
harmony.UpdateDataSet(data);
MyDataSet data2 = harmony.GetMyDataSetById(data.Id);
}
There is a compiler warning in Harmony.cs UpdateDataSet because the call is not awaited and execution will continue before the call is completed. This is affecting the program execution, because data2 is being retrieved before the update is taking place.
If I were to make UpdateDataSet async and add an await to it, then it just moves things up the stack a level, and now HarmonyScheduler gets the warning about not being awaited.
How do I wait for the update to be complete before retrieving data2, so that I will have the updated values in the data2 object?
How do I wait for the update to be complete before retrieving data2,
so that I will have the updated values in the data2 object?
The thing I see many people don't comprehend is the fact that using the TAP with async-await will infect your code like a plague.
What do I mean by that?
Using the TAP will cause async to bubble up all the way to the top of your call stack, that is why they say async method go "all the way". That is the recommendation for using the pattern. Usually, that means that if you want to introduce an asynchronous API, you'll have to provide it along side a separate synchronous API. Most people try to mix and match between the two, but that causes a whole lot of trouble (and many SO questions).
In order to make things work properly, you'll have to turn UpdateDataSet and GetMyDataSetById to be async as well. The outcome should look like this:
private readonly HttpClient httpClient = new HttpClient();
private async Task<string> GetDataSetAsync(string request)
{
httpClient.BaseAddress = theBaseAddress;
HttpResponseMessage response = await httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
private async Task PostDataSetAsync<T>(string request, T data)
{
client.BaseAddress = new Uri(theBaseAddress);
HttpResponseMessage response = await client.PostAsJsonAsync<T>(request, data);
response.EnsureSuccessStatusCode();
}
internal async Task<MyDataSet> GetMyDataSetByIdAsync(int id)
{
string request = String.Format("api/MyDataSet/GetById/{0}", id);
return JsonConvert.DeserializeObject<MyDataSet>(await GetDataSetAsync(request));
}
internal Task UpdateDataSetAsync(MyDataSet data)
{
return PostDataSetAsync("api/MyDataSet/Update", data);
}
Note - HttpClient is meant to be reused instead of a disposable, single call object. I would encapsulate as a class level field and reuse it.
If you want to expose a synchronous API, do so using a HTTP library that exposes a synchronous API, such as WebClient.
Always wait on the tasks right before you need its results.
Its always better to wait on a task if it contains an await in its body.
Warning : Do not use .Wait() or .Result
You would understand the concept better if you go through the control flow as explained Control Flow in Async Programs.
So in your case I would make all the functions accessing the async methods GetDataSet(string request) and PostDataSet<T>(string request, T data) with return type Task as awaitable.
Since you dont seem to expect any result back from the PostDataSet function you could just wait for it to complete.
PostDataSet("api/MyDataSet/Update", data).Wait();
How do I convert this chain of synchronous method calls into async (using the async/await operators)? Given that only the last call, DoRequest(), is the one that takes time to execute, is that the only method that needs to become async? Or do all the callers in the chain, RequestSomething() and Process(), need to be made async as well?
[HttpGet]
void Process()
{
var url = "http://someapi.com";
var myObject= RequestSomething(url);
//do something with the myObject.
}
MyObject RequestSomething(string url)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
var response = DoRequest(request);
return JsonConvert.DeserializeObject<MyObject>(response);
}
//method that takes time to return.
HttpResponseMessage DoRequest(HttpRequestMessage request)
{
var client = new HttpClient();
return client.SendAsync(request).Result;
}
To do async correctly it is "infectious", if you do it in one spot you need to do it all the way up the call chain to get any of the real benefits out of it. So whatever is calling Process() will need to handle the task returned from Process by either awaiting it or passing it up the chain like DoRequest does.
async Task Process()
{
var url = "http://someapi.com";
var myObject= await RequestSomething(url);
//do something with the myObject.
}
async Task<MyObject> RequestSomething(string url)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
var response = await DoRequest(request).ConfigureAwait(false);
return JsonConvert.DeserializeObject<MyObject>(response);
}
//method that takes time to return.
Task<HttpResponseMessage> DoRequest(HttpRequestMessage request)
{
var client = new HttpClient();
return client.SendAsync(request);
}
Because you do not do any extra work after performing the request you don't need async/await in your DoRequest function, but the other ones will need the async/await keywords. The .ConfigureAwait(false) makes it so that function does not have to run the rest of its code on the UI thread, this can give you a small performance boost. I did not know if the code that is in //do something with the myObject. required you being on the UI thread or not, so I did not put it on that await, but if you don't need to be on the UI thread you could add it there too.
You should make DoRequest...
Public async Task<HttpResponseMessage> DoRequest(...
Then return await client.SendAsync
Similarly, DoSomething should be async Task<...>
Your calling method, Process can be async void if you want to call it as fire and forget, otherwise an async Task.
Try:
var task = Task.Run(() => RequestSomething());
var task2 = Task.Run(() => RequestSomethingElse());
await Task.WhenAll(task, task2);
You can specify more than two if you like, or only one.