I am building an application using Xamarin (Android), it uses a PCL project as a Service layer. I have a Web Api endpoint and I am using HttpClient
to consume it.
Everything works fine, but if I leave my Android app open and idle for a while (like 2 minutes) and I try to make a new request, the first request using the singleton HttpClient
won't work. It just never returns and stays there until it timeouts (TaskCancelledException
). I also put a breakpoint on my Api and it doesn't get hit. If I try to send the request again, then it works.
After a lot of debugging I found that this only happens if I try to use the HttpClient
as a Singleton. If I create a new HttpClient
for every request everything works.
At first I thought this was a deadlock issue, I've done a lot of research and double checked everything following the guidelines described in this other answer and Stephen Cleary's excellent post and I'm almost sure this is not the case.
I'm using ConfigureAwait(false)
in every call from my PCL project so it doesn't capture the context.
The flow of a request goes like this:
Inside an Android Fragment:
SampleService svc = new SampleService();
response = await svc.GetAllSamples();
The service called (in my PCL project):
public class SampleService
{
public HttpClient Client { get; set; }
public SampleService()
{
// resolves my singleton instance and uses my custom DelegatingHandler
Client = CustomHttpClient.Instance;
}
public async Task<IEnumerable<Sample>> GetAllSamples()
{
IEnumerable<Sample> list = null;
// this never returns and timeouts the first time
using (var response = await Client.GetAsync("samples").ConfigureAwait(false))
{
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
lista = await Task.Run(() => JsonConvert.DeserializeObject<IEnumerable<Sample>>(json)).ConfigureAwait(false);
}
return list;
}
}
}
This is how I build my Singleton instance:
public sealed class CustomHttpClient
{
private static HttpClient _client;
public static HttpClient GetClient()
{
if (_client == null)
{
HttpMessageHandler messageHandler = new HttpClientHandler();
_client = new HttpClient(messageHandler);
_client.Timeout = TimeSpan.FromSeconds(30);
_client.BaseAddress = new Uri("myendpoint");
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
return _client;
}
}
I tried to simplify and isolate the code here, if I can provide any other useful snippets, just let me know.
Am I doing something wrong regarding singletons HttpClient
that I'm not aware of?
Update: Just for clarification, I'm trying to use HttpClient
as a Singleton just because, as I found in this answer by Darrel Miller and in the book Designing Evolvable Web APIs with ASP.NET (Chapter 14), they were designed to be reusable and thread-safe (in most of the cases). From my research I'm not using anything that is not thread-safe in it.