System.Net.Http.HttpRequestException

A base class for exceptions thrown by the System.Net.Http.HttpClient and System.Net.Http.HttpMessageHandler classes.

Minimum version: >= 4.5 >= Core 1.0

Statistics

18
elmah.io logo 8
17

How to handle it

try
{

}
catch (System.Net.Http.HttpRequestException e)
{

}
try
{

}
catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("something"))
{

}
try
{

}
catch (System.Net.Http.HttpRequestException e) when (LogException(e))
{

}

private static bool LogException(Exception e)
{
    logger.LogError(...);
    return false;
}

How to avoid it

We haven't written anything about avoiding this exception yet. Got a good tip on how to avoid throwing System.Net.Http.HttpRequestException? Feel free to reach out through the support widget in the lower right corner with your suggestions.

Links

YouTube videos

Possible fixes from StackOverflow

You are doing it right with ServerCertificateValidationCallback. This is not the problem you are facing. The problem you are facing is most likely the version of SSL/TLS protocol.

For example, if your server offers only SSLv3 and TLSv10 and your client needs TLSv12 then you will receive this error message. What you need to do is to make sure that both client and server have a common protocol version supported.

When I need a client that is able to connect to as many servers as possible (rather than to be as secure as possible) I use this (together with setting the validation callback):

  ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

It's probably caused by a local network connectivity issue (but also a DNS error is possible). Unfortunately HResult is generic, however you can determine the exact issue catching HttpRequestException and then inspecting InnerException: if it's a WebException then you can check the WebException.Status property, for example WebExceptionStatus.NameResolutionFailure should indicate a DNS resolution problem.


It may happen, there isn't much you can do.

What I'd suggest to always wrap that (network related) code in a loop with a try/catch block (as also suggested here for other fallible operations). Handle known exceptions, wait a little (say 1000 msec) and try again (for say 3 times). Only if failed all times then you can quit/report an error to your users. Very raw example like this:

private const int NumberOfRetries = 3;
private const int DelayOnRetry = 1000;

public static async Task<HttpResponseMessage> GetFromUrlAsync(string url) {
    using (var client = new HttpClient()) {
        for (int i=1; i <= NumberOfRetries; ++i) {
            try {
                return await client.GetAsync(url); 
            }
            catch (Exception e) when (i < NumberOfRetries) {
                await Task.Delay(DelayOnRetry);
            }
        }
    }
}

As you are using HttpClient, try to use response.EnsureSuccessStatusCode();

Now HttpClient will throw exception when response status is not a success code.

try
{
    HttpResponseMessage response = await client.GetAsync("http://www.ajshdgasjhdgajdhgasjhdgasjdhgasjdhgas.tk/");
    response.EnsureSuccessStatusCode();    // Throw if not a success code.

    // ...
}
catch (HttpRequestException e)
{
    // Handle exception.
}

ORIGINAL SOURCE OF THE CODE: http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client

You just need to keep digging. The exception "The response ended prematurely" isn't the root cause. Keep digging into the inner exceptions until you find the last one. You'll find this:

System.IO.IOException: Authentication failed because the remote party has closed the transport stream.

So it's not about your code. It seems the server you're hitting either can't handle the load, or is intentionally dropping your requests because you're hitting it too hard.

we resolved this problem with 2 code changes:

  1. Dispose of the httpResponseMessage and just work with a simple DTO

    using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
    {
        return await CreateDto(httpResponseMessage);
    }
    
  2. Downgrade the version of HTTP to v1.0

    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(url))
    {
        Version = HttpVersion.Version10,
        Content = httpContent
    };
    
    await client.SendAsync(httpRequestMessage);
    

which has the effect of adding this Http header

Connection: close 

rather than this

Connection: keep-alive