ahak
ahak

Reputation: 41

httpClient.GetAsync() timeout exception, if application idle a long time

I developed C# .net 4.6.1 application. In the application I use HttpClient for communicate with our backend API. Over time the application not sending the request to our backend (timeout exception is catched). The request is sent, after restart application.

Here is the snippet of our code.

class Program
{
  static void Main(string[] args)
  {
    MyClass myClass = GetAsync().Result;
  }

  private static async Task<MyClass> GetAsync()
  {
     MyClassResponse myClassResponse = await TestHttpClient.GetMyClassResponse();
    return MyClass.Create(myClassResponse);
  }
}
public static class TestHttpClient
{
   private static HttpClient _httpClient;

   public static void Init()
   {
     _httpClient = CreateHttpClient();
   }

   public static async Task<MyClassResponse> GetMyClassResponse()
   {
      HttpResponseMessage response = await GetRequestAsync("https://....");
      return await ParseToMyClassResponse<MyClassResponse>(response);
   }

   private static HttpClient CreateHttpClient()
   {
      HttpClient client = new HttpClient();
      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token .....");
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
      client.Timeout = TimeSpan.FromMilliseconds(10000);
      return client;
    }

    private static async Task<HttpResponseMessage> GetRequestAsync(string url)
   {
        try
        {
           return await _httpClient.GetAsync(new Uri(url));
         }
         catch (TaskCanceledException)
         {
          return new HttpResponseMessage(HttpStatusCode.RequestTimeout);
         }
    }

    private static async Task<T> ParseToMyClassResponse<T>(HttpResponseMessage response) where T : MyClassResponse, new()
        {
            T myClassResponse;
            try
            {
                string content = await response.Content.ReadAsStringAsync();
                response.EnsureSuccessStatusCode();
                myClassResponse = JsonConvert.DeserializeObject<T>(content);
                           }
            catch (Exception ex)
            {
                myClassResponse = new T();
            }

            response.Dispose();
            return myClassResponse;
        }
}

What am I doing wrong?

Upvotes: 0

Views: 8944

Answers (2)

ahak
ahak

Reputation: 41

I added logging and got following error:

System.Threading.Tasks.TaskCanceledException · A task was cancelled.

System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
TestHttpClient+<GetRequestAsync>d__20.MoveNext()

And I looked at the requests with using Fiddler, and got following results

  1. In normal mode fiddler shows 2 requests

    • Result=200, Protocol=HTTP, Host = Tunnel to, Url = api.example.com:443

      in SyntaxView tab: A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.

    • Result=200, Protocol=HTTPS, Host = api.example.com, Url = /test

  2. In failed mode Fiddler shows only 1 requst

    • Result=200, Protocol=HTTP, Host = Tunnel to, Url = api.example.com:443,

      in SyntaxView tab: After the client received notice of the established CONNECT, it failed to send any data

I would like to make a correction. In reality, I use the Init() method like this.

public static class TestHttpClient
{
   private static HttpClient _httpClient;

  public static void Init()
  {
    ServicePointManager.SecurityProtocol |= (SecurityProtocolType.Ssl3 | 
              SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | 
                                            SecurityProtocolType.Tls);
    ServicePointManager.DefaultConnectionLimit = 10;
    _httpClient = CreateHttpClient();
  }
}

Upvotes: 0

Gabriel Luci
Gabriel Luci

Reputation: 40958

A couple things I see:

First, your exception handler is ignoring the exception and throwing a new exception. Assign a variable to your TaskCanceledException and log that actual exception before you throw a new one. The inner exceptions might give you more information about what happened.

catch (TaskCancelledException e))
{
    Debug.WriteLine(e);
    //do whatever else
}

Side note: using new HttpResponseMessage(HttpStatusCode.RequestTimeout) is probably not the most appropriate thing. That makes it look like the server returned a 408 Request Timeout. When that's not really what happened.

A timeout that would throw a TaskCanceledException is when the client sent the request, but no response was received from the server in the time expected (30 seconds by default).

If that's truly the kind of timeout happening, then you may have to look at something like Wireshark or Fiddler to verify that the request is actually being sent. Then you would have to figure out what's different between that request and the request sent once you restart the application.

For example, is your token expired and restarting your application requests a new one? (that shouldn't result in a timeout, but if the server code is poorly written it could)

Upvotes: 2

Related Questions