133 lines
4.3 KiB
C#
133 lines
4.3 KiB
C#
|
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<string, HttpClientConfig> _configs = new ConcurrentDictionary<string, HttpClientConfig>();
|
|||
|
|
|||
|
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<HandlerFactory> HandlerFactories { get; private set; }
|
|||
|
|
|||
|
internal HttpClientConfig()
|
|||
|
{
|
|||
|
HandlerFactories = new List<HandlerFactory>();
|
|||
|
}
|
|||
|
|
|||
|
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();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|