使用async/await调用GetAsync/SendAsync的Singleton HttpClient永远不会返回

Mah*_*Ali 7 .net c# xamarin.android async-await dotnet-httpclient

我正在使用Xamarin(Android)构建应用程序,它使用PCL项目作为服务层.我有一个Web Api端点,我正在使用HttpClient它.

一切正常,但是如果我让我的Android应用程序打开并闲置一段时间(比如2分钟)并且我尝试发出新请求,那么使用单例的第一个请求HttpClient将无效.它永远不会返回并保持在那里直到超时(TaskCancelledException).我也在我的Api上设置了一个断点,它没有被击中.如果我再次尝试发送请求,那么它可以工作.

经过大量的调试后,我发现只有当我尝试使用HttpClient单例作为单例时才会发生这种情况.如果我HttpClient为每个请求创建一个新的一切都有效.

起初我认为这是一个僵局问题,我做了很多研究,并按照其他答案Stephen Cleary的优秀帖子所描述的指导原则进行了双重检查,我几乎可以肯定事实并非如此.
我正在使用ConfigureAwait(false)来自我的PCL项目的每次调用,因此它不会捕获上下文.

请求的流程如下:

在Android片段内:

SampleService svc = new SampleService();
response = await svc.GetAllSamples();
Run Code Online (Sandbox Code Playgroud)

这个服务叫(在我的PCL项目中):

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是我构建Singleton实例的方法:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图在这里简化和隔离代码,如果我可以提供任何其他有用的代码片段,请告诉我.

对于HttpClient我不知道的单身人士,我做错了吗?

更新:为了澄清,我试图使用HttpClientSingleton只是因为,正如我在Darrel Miller的回答中和在使用ASP.NET设计可演化的Web API(第14章)一书中所发现的那样,它们被设计为可重用的和线程安全(在大多数情况下).根据我的研究,我没有使用任何非线程安全的东西.