3
\$\begingroup\$

There has been talk recently of how we should be handling the lifetime of the System.Net.Http.HttpClient.

This article http://byterot.blogspot.co.uk/2016/07/singleton-httpclient-dns.html says that we should use it as a singleton, but we need to be careful about ensuring the connections are properly closed otherwise DNS changes won't be honoured.

I came up with the following message handler which can be injected in to an HttpClient to take care of setting the connection lease for each distinct scheme + host combination.

public class ServicePointManagingMessageHandler : HttpClientHandler
{
    private readonly ConcurrentDictionary<Uri, ServicePoint> _uriCache = new ConcurrentDictionary<Uri, ServicePoint>();
    private readonly int _oneMinuteInSeconds = (int)TimeSpan.FromMinutes(1).TotalSeconds;

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.RequestUri.IsAbsoluteUri)
        {
            var baseUri = new Uri($"{request.RequestUri.Scheme}://{request.RequestUri.Host}");

            _uriCache.AddOrUpdate(baseUri, uri =>
            {
                var sp = ServicePointManager.FindServicePoint(uri);
                sp.ConnectionLeaseTimeout = _oneMinuteInSeconds;

                return sp;
            }, (uri, point) => point);
        }

        return base.SendAsync(request, cancellationToken);
    }
}

Usage:

var client = new HttpClient(new ServicePointManagingMessageHandler());

I am wondering if the concept of intercepting the URI's as they come in to the HttpClient will allow the HttpClient to safely be used as a singleton without any of the issues listed in that article.

This gets around needing to know all hostnames that you might connect to at startup by intercepting calls - if people agree with this approach then it seems like it should become the accepted way to use the HttpClient for standard cases.

\$\endgroup\$
  • 1
    \$\begingroup\$ Hm, you are asking a question, yet there is not a single question mark to be found :). It would be good to state what specifically you'd like to get reviewed \$\endgroup\$ – ChrisWue Sep 2 '16 at 8:51
  • \$\begingroup\$ @ChrisWue obviously the entire thing. \$\endgroup\$ – Jeroen Vannevel Sep 2 '16 at 9:15
  • 1
    \$\begingroup\$ @ChrisWue I thought the question is always the same: how can I make my code better/prittier/faster/s.o.l.i.d-er etc... ;-) \$\endgroup\$ – t3chb0t Sep 2 '16 at 9:33
  • \$\begingroup\$ Haven't been active here for a while, but people were always encouraged to be more specific in terms of being a bit more specific what areas of review they like. I suppose this isn't a lot of code. \$\endgroup\$ – ChrisWue Sep 2 '16 at 9:34
  • \$\begingroup\$ Ha good point. Looks like I left a bit off the end explaining why I've written this - let me revise \$\endgroup\$ – James Hulse Sep 2 '16 at 10:22
1
\$\begingroup\$

Just a few things:

  1. You have already named the variable _oneMinuteInSeconds - I'd say you don't gain much by initializing it via a TimeSpan the way you do it. Just saying _oneMinuteInSeconds = 60 would be good enough since it's quite clear what the 60 stands for.

  2. Actually, according to MSDN the ConnectionLeaseTimeout is set in milliseconds as such your code is of by a factor of 1000 regarding the timeout (why the framework designers have not consistently used TimeSpan everywhere is a bit of a mystery to me).

\$\endgroup\$
  • \$\begingroup\$ Cheers - I'll fix those up. Do you agree with the general concept of putting this logic here? The article mentioned running this code for each hostname that you think you will connect to - I am trying to intercept the calls so you don't have to do that \$\endgroup\$ – James Hulse Sep 2 '16 at 10:22
  • \$\begingroup\$ @JamesHulse: Hm, sorry but I don't know enough about the internals of the HttpClient to assess that. \$\endgroup\$ – ChrisWue Sep 3 '16 at 1:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.