Awhile ago I implemented some code to consume a REST Api using the HttpClient
class.
using (var client = new HttpClient() { BaseAddress = new Uri(@"https://thirdparty.com") }) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(...); var uri = new Uri(@"rest/api/foo", UriKind.Relative); var content = new StringContent(json.ToString()); using (var response = await client.PostAsync(uri, content)) { // etc ... } }
This code seemed to work perfectly fine against both the test and production environments (each of which access a test/production uri). Recently, we started to get an HttpRequestException in the production environment only: System.Net.Http.HttpRequestException: Error while copying content to a stream.
This seemed a bit strange, so I used Postman to send the same message and it worked just fine. I wasn't sure why our code was failing and Postman was working. I changed a parameter in the json data (the state from "NY" to "NV") and our .NET code worked fine -- of course we can't just send the wrong json data, so this isn't a solution; this was more of an observation that the exact same code worked fine with different content.
What's interesting is that there are two code changes we could make that will resolve this. Firstly, Postman is able to generate working C# code using the RestSharp
package. Alternatively, I found an answer from another question pointing to using HttpVersion 1.0:
using (var request = new HttpRequestMessage(HttpMethod.Post, uri)) { request.Version = HttpVersion.Version10; request.Content = new StringContent(json.ToString()); using (var response = await client.SendAsync(request)) { // etc ... } }
The confusing part is that Postman uses the HTTP/1.1 version. So, in summary:
Why on earth is Postman able to work using HTTP/1.1 but HttpClient fails? Is this a problem with our client (the code works for other US States)? Is this a bug in the .NET Framework? Is there something wrong with the implementation/hosting of the REST Api from the third party?
Postman headers:
POST rest/api/foo HTTP/1.1 Host: thirdparty.com Content-Type: application/json Authorization: Basic SOME_ENCRYPTED_USER_PASS Cache-Control: no-cache Postman-Token: 2fa5b5a0-b5d3-bd4c-40f0-d2b55b60316b
Sample Json:
{ "stateCode": "NY", "packageID": "58330", "name": "58330-PRI-1", "documents": [ { "type": "SPECIAL", "name": "Sample Document", "documentID": "3569976" } ], "descriptions": [ { "city": "New York", "state": "NY" } ] }
Stacktrace:
AggregateException: One or more errors occured. HttpRequestException: Error while copying content to a stream. IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. SocketException: An existing connection was forcibly closed by the remote host.
Due to the fact that you can change the data slightly and have it succeed, I would say your issues has nothing to do with any of your code. What if their server has cached a bad value and will continue sending you that value until their cache clears?
Try implicitly telling the server not to use cached values...
using (var client = new HttpClient() { BaseAddress = new Uri(@"https://thirdparty.com") }) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(...); var uri = new Uri(@"rest/api/foo", UriKind.Relative); var content = new StringContent(json.ToString()); client.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache"); using (var response = await client.PostAsync(uri, content)) { // etc ... } }
and see if you get a valid response stream.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With