-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Original issue by @tekian
Background and motivation
The purpose of the new API, represented by the HttpClientSocketHandlingExtensions, SocketsHttpHandlerBuilder and SocketsHttpHandlerOptions classes, is to provide a more convenient and fluent way to configure SocketsHttpHandler instances for named HttpClient instances in applications that use dependency injection and the IHttpClientFactory.
API Proposal
public class SocketsHttpHandlerOptions
{
public bool AllowAutoRedirect { get; set; }
public bool UseCookies { get; set; }
public int MaxConnectionsPerServer { get; set; }
public DecompressionMethods AutomaticDecompression { get; set; }
public TimeSpan ConnectTimeout { get; set; }
public TimeSpan PooledConnectionLifetime { get; set; }
public TimeSpan PooledConnectionIdleTimeout { get; set; }
#if NET5_0_OR_GREATER
public TimeSpan KeepAlivePingDelay { get; set; }
public TimeSpan KeepAlivePingTimeout { get; set; }
#endif
}
public class SocketsHttpHandlerBuilder
{
public string Name { get; }
public IServiceCollection Services { get; }
public SocketsHttpHandlerBuilder ConfigureHandler(Action<SocketsHttpHandler> configure) {}
public SocketsHttpHandlerBuilder ConfigureHandler(Action<IServiceProvider, SocketsHttpHandler> configure) {}
public SocketsHttpHandlerBuilder ConfigureOptions(IConfigurationSection section) {}
public SocketsHttpHandlerBuilder ConfigureOptions(Action<SocketsHttpHandlerOptions> configure) {}
}
public static class HttpClientSocketHandlingExtensions
{
public static IHttpClientBuilder AddSocketsHttpHandler(this IHttpClientBuilder builder) {}
public static IHttpClientBuilder AddSocketsHttpHandler(this IHttpClientBuilder builder, Action<SocketsHttpHandlerBuilder> configure) {}
}API Usage
{
"HttpClientSettings": {
"MyClient": {
"AllowAutoRedirect": true,
"UseCookies": true,
"ConnectTimeout": "00:00:05"
}
}
}public void ConfigureServices(IServiceCollection services)
{
IConfiguration configuration = ...;
services
.AddHttpClient("MyClient")
.AddSocketsHttpHandler(builder =>
{
builder.ConfigureOptions(configuration.GetSection("HttpClientSettings:MyClient"));
});
}Additionally, we could consider also adding following convenience methods:
public class SocketsHttpHandlerBuilder
{
public SocketsHttpHandlerBuilder ConfigureClientCertificate(Func<IServiceProvider, X509Certificate2> clientCertificate) { ...}
public SocketsHttpHandlerBuilder DisableRemoteCertificateValidation() { ... }
}....either in this form or as an extension methods.
Alternative Designs
No response
Risks
No response
Background and motivation
The purpose of the new API, represented by the ISocketsHttpHandlerBuilder, SocketsHttpHandlerBuilderExtensions and UseSocketsHttpHandler, is to provide a more convenient and fluent way to configure SocketsHttpHandler instances for named HttpClient instances in applications that use dependency injection and the IHttpClientFactory. One of the main asks is to be able to configure SocketsHttpHandler via a configuration file.
This is a convenience API for some of the most widely used basic scenarios investigated by dotnet/extensions team.
While it is possible to achieve the same result by existing methods, the API significantly simplifies it in the common scenarios.
Note: this API is .NET 5+ only.
API Proposal
namespace Microsoft.Extensions.DependencyInjection;
// existing
public static class HttpClientBuilderExtensions
{
#if NET5_0_OR_GREATER
// new
[UnsupportedOSPlatform("browser")]
public static IHttpClientBuilder UseSocketsHttpHandler(this IHttpClientBuilder builder,
Action<SocketsHttpHandler, IServiceProvider>? configureHandler = null) {}
[UnsupportedOSPlatform("browser")]
public static IHttpClientBuilder UseSocketsHttpHandler(this IHttpClientBuilder builder,
Action<ISocketsHttpHandlerBuilder> configureBuilder) {}
#endif
// existing (+2 overloads)
// public static IHttpClientBuilder ConfigurePrimaryHttpMessageHandler(this IHttpClientBuilder builder, Func<HttpMessageHandler> configureHandler) {}
}
#if NET5_0_OR_GREATER
// new
public interface ISocketsHttpHandlerBuilder
{
string Name { get; }
IServiceCollection Services { get; }
}
// new
public static class SocketsHttpHandlerBuilderExtensions
{
[UnsupportedOSPlatform("browser")]
public static ISocketsHttpHandlerBuilder Configure(this ISocketsHttpHandlerBuilder builder,
Action<SocketsHttpHandler, IServiceProvider> configure) {}
[UnsupportedOSPlatform("browser")]
public static ISocketsHttpHandlerBuilder Configure(this ISocketsHttpHandlerBuilder builder,
IConfigurationSection configurationSection) {}
}
#endifAPI Usage
// uses SocketsHttpHandler as a primary handler
services.AddHttpClient("foo")
.UseSocketsHttpHandler();
// sets up properties on the handler directly
services.AddHttpClient("bar")
.UseSocketsHttpHandler((handler, _) =>
{
handler.PooledConnectionLifetime = TimeSpan.FromMinutes(2);
handler.UseCookies = false;
handler.MaxConnectionsPerServer = 1;
});
// loads properties from config file and chains setting up SslOptions via builder
services.AddHttpClient("baz")
.UseSocketsHttpHandler(builder =>
builder.Configure(configuration.GetSection("HttpClientSettings:baz"))
.Configure((handler, _) => handler.SslOptions = new SslClientAuthenticationOptions
{
RemoteCertificateValidationCallback = delegate { return true; },
})
);{
"HttpClientSettings": {
"baz": {
"AllowAutoRedirect": true,
"UseCookies": false,
"ConnectTimeout": "00:00:05"
}
}
}Illustrative only: additional extension methods
services.AddHttpClient("qux")
.UseSocketsHttpHandler(builder =>
builder.Configure(configuration.GetSection("HttpClientSettings:qux"))
.SetMaxConnectionsPerServer(1)
.DisableRemoteCertificateValidation()
);
// e.g. added by user or a 3rd party lib
public static class MyFluentSocketsHttpHandlerBuilderExtensions
{
public static ISocketsHttpHandlerBuilder DisableRemoteCertificateValidation(this ISocketsHttpHandlerBuilder builder, bool allowAutoRedirect) {}
public static ISocketsHttpHandlerBuilder ConfigureClientCertificate(Func<IServiceProvider, X509Certificate> clientCertificate) {}
// ...
public static ISocketsHttpHandlerBuilder SetAllowAutoRedirect(this ISocketsHttpHandlerBuilder builder, bool allowAutoRedirect) {}
public static ISocketsHttpHandlerBuilder SetUseCookies(this ISocketsHttpHandlerBuilder builder, bool useCookies) {}
public static ISocketsHttpHandlerBuilder SetMaxConnectionsPerServer(this ISocketsHttpHandlerBuilder builder, int maxConnectionsPerServer) {}
public static ISocketsHttpHandlerBuilder SetConnectTimeout(this ISocketsHttpHandlerBuilder builder, TimeSpan connectTimeout) {}
public static ISocketsHttpHandlerBuilder SetPooledConnectionLifetime(this ISocketsHttpHandlerBuilder builder, TimeSpan pooledConnectionLifetime) {}
public static ISocketsHttpHandlerBuilder SetPooledConnectionIdleTimeout(this ISocketsHttpHandlerBuilder builder, TimeSpan pooledConnectionIdleTimeout) {}
public static ISocketsHttpHandlerBuilder SetKeepAlivePingDelay(this ISocketsHttpHandlerBuilder builder, TimeSpan keepAlivePingDelay) {}
public static ISocketsHttpHandlerBuilder SetKeepAlivePingTimeout(this ISocketsHttpHandlerBuilder builder, TimeSpan keepAlivePingTimeout) {}
// ...
}