Reputation: 41
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
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
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
In failed mode Fiddler shows only 1 requst
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
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