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\$
7
  • 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, 2016 at 8:51
  • \$\begingroup\$ @ChrisWue obviously the entire thing. \$\endgroup\$ Sep 2, 2016 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, 2016 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, 2016 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\$ Sep 2, 2016 at 10:22

1 Answer 1

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\$
2
  • \$\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\$ Sep 2, 2016 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, 2016 at 1:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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