Skip to content

Instantly share code, notes, and snippets.

@gubenkoved
Last active March 12, 2019 18:49
Show Gist options
  • Save gubenkoved/c37d55bc4d04f806b566a81dc7dd0cca to your computer and use it in GitHub Desktop.
Save gubenkoved/c37d55bc4d04f806b566a81dc7dd0cca to your computer and use it in GitHub Desktop.
safe-http-client
/// <summary>
/// This static wrapper around HttpClient allows to avoid issue with exhausting
/// outgoing sockets via reusing single instance of that. Additionally, it addresses
/// issue caused by resusing connections -- skipping DNS changes via limiting connection
/// lifespan.
/// See for details:
/// https://blogs.msdn.microsoft.com/shacorn/2016/10/21/best-practices-for-using-httpclient-on-services/
/// http://byterot.blogspot.ru/2016/07/singleton-httpclient-dns.html
/// </summary>
public class SafeHttpClient
{
private static class ServicePointManagerConfigurator
{
private static object _syncRoot = new object();
private static HashSet<string> _configuredHosts = new HashSet<string>();
public static void EnsureConfigured(Uri uri)
{
string host = uri.Host;
lock (_syncRoot)
{
if (!_configuredHosts.Contains(host))
{
Trace.WriteLine($"Configure {host} host to limit connection lifetime to pick up DNS changes");
// limit connection lifespan to DNS refresh timeout (2 minutes)
ServicePointManager.FindServicePoint(uri).ConnectionLeaseTimeout = ServicePointManager.DnsRefreshTimeout;
_configuredHosts.Add(host);
}
}
}
}
private HttpClient _httpClient = new HttpClient();
public static readonly SafeHttpClient Instance = new SafeHttpClient();
private SafeHttpClient() { }
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
{
ServicePointManagerConfigurator.EnsureConfigured(request.RequestUri);
return _httpClient.SendAsync(request);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment