using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net.Http; namespace Http.Core { public class HttpClientFactory : IDisposable { private HttpClientFactory() { } private static readonly object _instanceLock = new object(); private static HttpClientFactory _instance; public static HttpClientFactory Instance { get { if (_instance == null) { lock (_instanceLock) { if (_instance == null) _instance = new HttpClientFactory(); } } return _instance; } } public void Dispose() { foreach (var config in _configs) { config.Value.Dispose(); } _configs.Clear(); } private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); public delegate void ConfigureBuilder(HttpClientBuilder builder); public static HttpClientBuilder AddHttpClient(string name) { var builder = new HttpClientBuilder(); _ = Instance._configs.TryAdd(name, builder.Config); return builder; } public static HttpClient CreateClient(string name) { if (!Instance._configs.ContainsKey(name)) _ = Instance._configs.TryAdd(name, new HttpClientConfig()); var config = Instance._configs[name]; var client = new HttpClient(config.Handler, false); config.ConfigureClient?.Invoke(client); return client; } public delegate void ConfigureClient(HttpClient client); public delegate DelegatingHandler HandlerFactory(); public class HttpClientBuilder { internal HttpClientConfig Config { get; } = new HttpClientConfig(); public HttpClientBuilder AddConfigureClient(ConfigureClient configureClient) { Config.ConfigureClient += configureClient; return this; } public HttpClientBuilder AddHttpMessageHandler(HandlerFactory configureHandler) { Config.HandlerFactories.Add(configureHandler); return this; } } internal class HttpClientConfig : IDisposable { internal ConfigureClient ConfigureClient { get; set; } internal ICollection HandlerFactories { get; private set; } internal HttpClientConfig() { HandlerFactories = new List(); } private readonly object _handlerLock = new object(); private HttpMessageHandler _handler; internal HttpMessageHandler Handler { get { if (_handler == null) { lock (_handlerLock) { if (_handler == null) _handler = BuildHandler(); } } return _handler; } } private HttpMessageHandler BuildHandler() { if (HandlerFactories == null || !HandlerFactories.Any()) return new HttpClientHandler(); DelegatingHandler handler, intermediate; handler = intermediate = HandlerFactories.First().Invoke(); foreach (var handlerFactory in HandlerFactories.Skip(1)) { intermediate.InnerHandler = handlerFactory(); intermediate = intermediate.InnerHandler as DelegatingHandler; } intermediate.InnerHandler = new HttpClientHandler(); return handler; } public void Dispose() { ConfigureClient = null; HandlerFactories?.Clear(); HandlerFactories = null; _handler?.Dispose(); } } } }