HttpClient.PostAsJsonAsync never sees when a message succeeds and responds

We use HttpClient to publish json for a relaxed web service. In one case, we are faced with something that puzzled us. Using tools such as the postman, script, etc., we can publish it to the end point and see that it works. When we do the same with HttpClient.PostAsJsonAsync, we can check in the software that we send that it received the data just fine. However, our PostAsJsonAsync will always end up with a timeout and not give us an answer.

We worked with the team that created the service we consume, plus our additional testing on our side, and we have not yet been able to truly time out this service.

Every time we make a message with the HttpClient, we can verify that the target software that we publish is actually receiving data. Each time we send a message to this target software from any other tool, we always very quickly see a response with a status code of 200. Something about HttpClient does not accept a response from this particular service. Does anyone have an idea what we can look at here?

Here's the code (although it's such a cookie cutter that I almost don't feel it necessary)

public string PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1) { using (var client = new HttpClient()) { if (timeoutMinutes > 0) { client.Timeout = new TimeSpan(0,timeoutMinutes,0); } var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath; var response = client.PostAsJsonAsync(useUrl, o).Result; if(response.StatusCode == System.Net.HttpStatusCode.OK) { return response.Content.ReadAsStringAsync().Result; } return ""; } } 
+7
c # async-await connection-timeout
source share
5 answers
 System.Net.ServicePointManager.Expect100Continue = false; 

This line of code in our case fixed the problem. A developer from another team suggested this proposal, and it works. I still need to do this and read enough on it to give an explanation of what this is about.

0
source

It:

 var response = client.PostAsJsonAsync(useUrl, o).Result; 

Causes a code lock. This often happens when blocking asynchronous APIs and why you experience the effect "I can not see the answer."

How does this cause a dead end? The fact that you are executing this request in an environment that contains a synchronization context, perhaps the one that belongs to the user interface. It executes the async request, and when the response arrives, it continues through the I / O completion thread, which attempts to send the continuation to the same UI context that is currently blocked by your .Result call.

If you want to make an HTTP request synchronously, use WebClient . If you want to use the asynchronous API correctly, then await instead of a block with .Result .

+8
source

Is there a reason why you are not following the asynchronous wait pattern? You call the async method, but do not expect it. You did not say that the code calling your REST service was a Windows Forms or ASP.NET application, but that .Result is probably causing problems .

Can you restructure your method as follows:

 public async Task<string> PostData(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1) { using (var client = new HttpClient()) { if (timeoutMinutes > 0) { client.Timeout = new TimeSpan(0,timeoutMinutes,0); } var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath; var response = await client.PostAsJsonAsync(useUrl, o); if(response.StatusCode == System.Net.HttpStatusCode.OK) { return await response.Content.ReadAsStringAsync(); } return ""; } } 
+3
source

I had the same problem and this SO was answered for me.

In a nutshell, you need to use the ConfigureAwait(false) extension to avoid a dead end:

 var response = await client.PostAsJsonAsync(useUrl, o).ConfigureAwait(false); 
+3
source

This is a small modification to @Justin Helgerson's solution. There are 2 call blocking in your method .Result ; as soon as you start asynchronous mode, you should fix both of them.

 public async Task<string> PostDataAsync(string resourcePath, Object o, Boolean isCompleteUrl = false, int timeoutMinutes = -1) { using (var client = new HttpClient()) { if (timeoutMinutes > 0) { client.Timeout = new TimeSpan(0,timeoutMinutes,0); } var useUrl = isCompleteUrl ? resourcePath : ApiBase + resourcePath; var response = await client.PostAsJsonAsync(useUrl, o); if(response.StatusCode == System.Net.HttpStatusCode.OK) { return await response.Content.ReadAsStringAsync(); } return ""; } } 

Note. I also renamed the method to PostDataAsync according to the TAP pattern.

+1
source

All Articles