vendredi 24 novembre 2017

HttpClient Singleton - DNS changes are NOT honoured

I've read a few articles and the pitfalls of using a static HttpClient and the solution. One of the articles being - http://ift.tt/2zm4mYX

I've implemented the solution and want to test to ensure that what the article proposed will actually work.

The following is the code that we are trying to avoid:

        Task.Run(async () =>
        {
            using (var httpClient = new HttpClient(new ApiHandler()))
            {
                var httpResponse = await httpClient.GetAsync("http://ift.tt/2BjLhYF");
                var result = await httpResponse.Content.ReadAsStringAsync();
                Console.WriteLine(result);
            }
        }).ContinueWith(async task =>
        {
            await Task.Delay(5000);
            using (var httpClient = new HttpClient(new ApiHandler()))
            {
                var httpResponse = await httpClient.GetAsync("http://ift.tt/2BjLhYF");
                var result = await httpResponse.Content.ReadAsStringAsync();
                Console.WriteLine(result);
            }
        }).ContinueWith(async task =>
        {
            await Task.Delay(10000);
            using (var httpClient = new HttpClient(new ApiHandler()))
            {
                var httpResponse = await httpClient.GetAsync("http://ift.tt/2BjLhYF");
                var result = await httpResponse.Content.ReadAsStringAsync();
                Console.WriteLine(result);
            }
        });

When I view the traffic in fiddler:

enter image description here

The behavior is as expect. Each create and dispose forces a connection to be established when the the request and response are completed.

The proper and proposed way to use the HttpClient is to for it to be static:

    private static readonly HttpClient HttpClient = new HttpClient(new ApiHandler());
    static void Main()
    {
        ServicePointManager
            .FindServicePoint(new Uri("https://test.com"))
            .ConnectionLeaseTimeout = 1000; // 1 second
        ServicePointManager.DnsRefreshTimeout = 1000; // 1 second

        Task.Run(async () =>
        {
            var httpResponse = await HttpClient.GetAsync("http://ift.tt/2BjLhYF");
            var result = await httpResponse.Content.ReadAsStringAsync();
            Console.WriteLine(result);
        }).ContinueWith(async task =>
        {
            await Task.Delay(5000); // delay 5 seconds
            var httpResponse = await HttpClient.GetAsync("http://ift.tt/2BjLhYF");
            var result = await httpResponse.Content.ReadAsStringAsync();
            Console.WriteLine(result);
        }).ContinueWith(async task =>
        {
            await Task.Delay(10000); // delay 10 seconds
            var httpResponse = await HttpClient.GetAsync("http://ift.tt/2BjLhYF");
            var result = await httpResponse.Content.ReadAsStringAsync();
            Console.WriteLine(result);
        });

        Console.ReadKey();
    }

I'd expect the same behavior as the previous image however it looks like the following:

enter image description here

And if I then add HttpClient.DefaultRequestHeaders.ConnectionClose = true; I get the desired outcome however this is what we want to avoid - for each request response to create a connection.

So is my desired outcome in Fiddler correct? or am I missing something with setting the ConnectionLeaseTimeout and/or DnsRefreshTimeout? I'd really like to test this behavior and ensure that setting those properties on ServicePointManager resolves the know DNS issue with a static instance of HttpClient.

Aucun commentaire:

Enregistrer un commentaire