I have the following piece of code in a domain service:
HttpClient client = new HttpClient();
client.GetAsync("http://somewebsite.com").Result;
Which works fine, I can place a break point on followed lines and they do hit and all is good. However, I have the same line of code in a nuget package installed in this very same project. There there's the exact same http call:
public class Client : Base
{
public Task<List<Stuff>> GetAsync()
{
return SendMessageAsync(HttpMethod.Get, "http://getstuff.com")
.ContinueWith(x => JsonConvert.DeserializeObject<List<StuffView>>(x.Result.Content.ReasAsStringAsync().Result);
}
}
public class Base
{
HttpClient client:
public Base(HttpClient client)
{
this.client = client:
}
protected async Task<HttpResponseMessage> GetMessageAsync(BttpMethod method, string url)
{
var request = CreateRequestAsync(method, url);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.SendAsync(request); //line 1
return response; // Line 2
}
protected HttpRequestMessage CreateRequestAsync(HttpMethod method, string url)
{
var request = new HttpRequestMessage(method, url);
request.SetBearerToken(myAccessTokenProvider);
return request;
}
}
This is how my domain service is using the nuget package code:
var client = factory.Create();
client.GetAsync().Result;
Debugging this code shows that inside Base class line 1 is hit but line 2 never does. Searching on internet it seems like a thread deadlock issue. So my question is, assuming it's a deadlock, why the heck the first http call in domain service works but not the second one that uses the nuget package code?!
HttpClient deadlock issue:
HttpClient.GetAsync(...) never returns when using await/async
The first example works because either the Task is in the .Completed == true state before you call .Result on it or that line of code has SyncronisationContext.Current == null.
If the task is not in the completed state calling .Result or .Wait() on a task can result in a deadlock if SyncronisationContext.Current != null at the point you called .Result or .Wait(). The best thing to do is mark the entire call stack as async and start returning Task instead of void and Task<T> where you return T then calling await on all places you used .Result or .Wait().
If you are not willing to make those code changes you must switch to using non async methods, this will requite switching from HttpClient to WebClient and using it's non async method calls to do your requests.
Do not use .Result. With .Result, the I/O is started (asynchronously) where the calling thread (synchronously) blocks waiting for it to complete.
Just use await.
var stuff = await client.GetAsync();
Related
I am stuck on an issue that may be conceptual or something simple I am missing. I have a Desktop application that is making an async call to the server.
This involves multiple nested calls through several classes. I have kept it async the whole way down the call chain.
The main issue which I have been able to reproduce consistently is when I am passing an HTTP client to another service which makes an async Post.
The code snippets aren't %100 correct as is, just trying to show basic
public async Task<bool> SomeTask(IEnumerable<Dto> dtoList)
{
var response = await _corepointService.PostCore(request, _idbContext);
if (response.StatusCode == HttpStatusCode.BadRequest)
{
success = false;
}
}
return success;
}
public Task<HttpResponseMessage> PostCore(Dto request, IDBContext
dbContext, HttpClient _httpClient)
{
var dto = new HttpRequestMessage
{
RequestUri = new Uri(request.Resource),
Method = HttpMethod.Post,
Content = new StringContent(request.Body, Encoding.UTF8,
"application/json")
};
return _httpClient.SendAsync(dto);
}
This is the other alternative I have tried, not passingin the HttpClient and creating a new one.
public Task<HttpResponseMessage> PostCore(Dto request, IDBContext
dbContext)
{
var _httpClient = new HttpClient();
var dto = new HttpRequestMessage
{
RequestUri = new Uri(request.Resource),
Method = HttpMethod.Post,
Content = new StringContent(request.Body, Encoding.UTF8,
"application/json")
};
return _httpClient.SendAsync(dto);
}
The error I am getting is
WCF HandleError - System.InvalidOperationException: A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled).
at System.Threading.Tasks.Task.Dispose(Boolean disposing)
at System.Threading.Tasks.Task.Dispose()
at System.ServiceModel.Dispatcher.MessageRpc.DisposeParametersCore(Boolean excludeInput)
WCF HandleError - System.InvalidOperationException: A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled).
at System.Threading.Tasks.Task.Dispose(Boolean disposing)
at System.Threading.Tasks.Task.Dispose()
at System.ServiceModel.Dispatcher.MessageRpc.DisposeParametersCore(Boolean excludeInput)
WCF HandleError - System.InvalidOperationException: A task may only be disposed if it is in a completion state (RanToCompletion, Faulted or Canceled).
at System.Threading.Tasks.Task.Dispose(Boolean disposing)
at System.Threading.Tasks.Task.Dispose()
at System.ServiceModel.Dispatcher.MessageRpc.DisposeParametersCore(Boolean excludeInput)
I am consistenly getting this error when the Async Post is being made in the final service. I am just not sure if it is even related, or is some kind of race relation. Any help or links to async information is much appreciated. I have tried to find any related posts on SO and didn't find anything specifically regarding this.
Thanks!
Please ensure the following:
async in PostCore method definition
public async Task<HttpResponseMessage> PostCore(Dto request,
IDBContext dbContext, HttpClient _httpClient){}
and 'await' the SendAsync call
return await _httpClient.SendAsync(dto);
Hope this helps!
This was caused by a wrapper class in the Desktop client that was returning a task and expecting the method it was awaiting to be synchronous.
It was unrelated to the HttpPost or any of the async code in the server itself.
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'm using HttpClient to post data to a webapi application.
This code works (the web api receives the post call), but the code is waiting for a response.
public static async void Notify(List<string> txs,string url)
{
using (HttpClient client = new HttpClient() )
{
string resourceAddress = url;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
await client.PostAsJsonAsync(resourceAddress, txs);
}
}
This one doesn't wait for a response from the web api but the web api doesn't get any post call:
public static void Notify(List<string> txs,string url)
{
using (HttpClient client = new HttpClient() )
{
string resourceAddress = url;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.PostAsJsonAsync(resourceAddress, txs);
}
}
I need to call the web api and continue execution of code without waiting.
How do I do that with HttpClient ?
And I want to the method to finish execute (not include to other work inside)
I need to call the web api and continue execution of code without
waiting. How do I do that with HttpClient ?
When you call Notify, it should be returning a System.Threading.Task, this task is the wrapper that is managing the execution of your Notify method, and in turn the PostAsJsonAsync method.
public static async Task Notify(List<string> txs,string url)
{
using (HttpClient client = new HttpClient() )
{
string resourceAddress = url;
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
return client.PostAsJsonAsync(resourceAddress, txs);
}
}
You might be calling Notify with an await. This will pause the method calling Notify at the place of calling (and the calling method to this will continue). If you do not await you can execute other code, and then after this has completed you can then await the task from Notify and wait for the Post to finish. You will need to wait for the post to finish at somepoint, unless the extra work runs longer than the post task itself. e.g
var task = Notify(someList, someUrl);
// do a long running task / extra work here,
// we have not awaited Notify therefore this will execute whilst the post
// is running
await task;
// at this point the we have waited for the Notify method to complete,
// this will block for the time the post has left to complete (if any at all)
await is telling your method to pause execution at this point and wait for the task to complete. BUT if there is a calling method then the calling method continues whilst it is waiting. If the calling method also awaits then this waits until the task completes, and the next method up the call stack continues, and so forth until we leave the code stack and end up in some sort of non blocking layer waiting for code to complete (e.g Async ASP.NET MVC, or Async Winforms UI). Or we have an explicit blocking Task.Wait call.
If anyone still looking for an answer,
public void NotifyAsyncWrapper(IEnumerable<string> txs, string url)
{
Notify(txs, url).ContinueWith(ContinuationAction, TaskContinuationOptions.OnlyOnFaulted);
}
public async Task Notify(IEnumerable<string> txs, string url)
{
//async await code
}
private void ContinuationAction(Task task)
{
if (task.Exception != null)
{
logger.LogError(ex, ex.Message);
}
}
I'm doing an HttpRequest to an Url that returns me an xml content. So I try to make an asynchronous request but during this request the application is stopped (pause) and it seems that it cannot get a response (the url inside a browser works perfectly and it returns what I expected).
Here is my code:
public static async Task<String> getResponse(String url)
{
HttpClient httpClient = new HttpClient();
HttpResponseMessage request = await httpClient.GetAsync(url);
String stream = await request.Content.ReadAsStringAsync();
return stream;
}
and I take this with:
String response = UtilityClass.getResponse(requestUrl).Result;
Anyone can help me please?
What happends here is a deadlock. Without too much information i see you're blocking on an asynchronous operation when calling
string response = UtilityClass.getResponse(requestUrl).Result
What happends is when you await inside getResponse, the TaskAwaitable being generated captures your SynchronizationContext in order to marshal the continuation back on to the same context in which it was called. But, when it trys to marshal work bacl to the captured context it cant, because Result is blocking the thread. This is why you should never block on async code. This can be fixed by using ConfigureAwait(false) which tells the TaskAwaitable not to marshal the continuation back and simply execute on the current thread that invoked it:
public static async Task<String> getResponse(String url)
{
HttpClient httpClient = new HttpClient();
HttpResponseMessage request = await httpClient.GetAsync(url).ConfigureAwait(false);
String stream = await request.Content.ReadAsStringAsync().ConfigureAwait(false);
return stream;
}
Another solution, which is better IMO, is to use the async method properly and await on it, instead of block:
string response = await UtilityClass.getResponse(requestUrl)
That would require you to add the async keyword to the calling method. If you cant, maybe a synchronous http request might be the better solution.
Edit
To quote #EricLippert comment which makes this easier to understand:
The key thing to understand here is that result = task.Result; means do nothing else until the result is available, and result = await task; means do something else until the result is available. Both turn a Task<string> into a string, but one blocks and the other does not
There are many good posts explaining the fundamental s of async/await:
Asynchronous Programming with Async and Await
Asynchrony in C# 5 Series (Eric Lippert)
Async Await Intro (Stephan Cleary)
Async Await FAQ
I am facing problem in calling HttpClient class and async call. I call the function List() from page_load. The calls return from the line HttpResponseMessage response = await client.GetAsync(str); and never comes back to finish it.
I don't understand what mistake I am doing. Following is my code:
protected void Page_Load(object sender, EventArgs e)
{
Task<string> s= List(product);
}
protected async Task<string> List(string ProductType)
{
string str = "http://xx.xx.com/wiki/api.php";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(String.Format("{0}:{1}", "username", "password"))));
HttpResponseMessage response = await client.GetAsync(str);
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
}
return content;
}
It never executes following lines.
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
Please help. Thanks in advance.
You never show what happens to the task in Page_Load, but given your symptoms and the fact that Page_Load is not async, I'm betting that you're calling Result or Wait instead of awaiting it.
When you do that, you cause a deadlock. The link to my blog explains this in detail, but the gist is that await will capture and restore the current "context". In ASP.NET, this is a request context, and the request context only allows one thread executing in it at a time. So, if you call Result or Wait (while you're in the request context), you'll block a thread in that request context until the Task<string> completes. Meanwhile, when the HttpClient gets its response, it tries to resume after the await client.GetAsync(str). But the request context will only allow one thread in at a time, and that thread is blocked waiting for the Task to complete. Since List cannot complete because the context is busy, you have a deadlock.
To prevent deadlocks, follow these two best practices (from my recent MSDN article):
Use async all the way. That is, use await instead of Result or Wait.
Use ConfigureContext(false) in your "library" code, i.e., every await in List should actually be await ... .ConfigureAwait(false);