I want to pass HttpMessageHandler
into my HttpClient
. The main reason is to pass the proxy (IWebProxy
).
Ideally, HttpClient
is defined in constructor like this (Using DI):
public class MyApiClient : IMyApiClient
{
private readonly HttpClient _httpClient;
public MyApiClient(HttpClient httpClient)
{
// I am not sure how to pass `handler` here.
_httpClient = httpClient;
}
}
The way I am adding proxy into HttpClient
is as following (Not using DI):
public class MyApiClient : IMyApiClient {
private readonly HttpClient _httpClient;
public MyApiClient() {
var proxy = new WebProxy {
Address = new Uri("http://test.com:1234"),
BypassProxyOnLocal = false,
UseDefaultCredentials = false,
};
// Create a client handler that uses the proxy
var httpClientHandler = new HttpClientHandler {
Proxy = proxy,
};
// Disable SSL verification
httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
_httpClient = new HttpClient(handler: httpClientHandler, disposeHandler: true);
}
}
Questions:
- Is my approach correct to pass proxy?
- Is it possible to pass proxy in
HttpClient
using DI (first approach)?
CodePudding user response:
Manually handling either HttpClient
or the underlying HttpMessageHandler
is considered a bad practice in general due to the way the low level socket resources are managed: in most cases, it would either lead to socket starvation due to leaks, or it could lead to unusable failed connections.
Instead, you should rely on IHttpClientFactory
and related abstractions. First, I'd strongly recommend reading the guidelines from Microsoft themselves here:
The simplest possible way to configure a single handler is to use the AddHttpClient
overload. In your case, it would look something like the following:
services
.AddHttpClient<IMyApiClient, MyApiClient>((provider, client) =>
{
// Confiure one-off settings of the client here.
// There is an overload which doesn't pass the 'provider', in case
// you don't need DI during the configuration.
//
// For example (using recommended 'IOptions' approach):
var settings = provider.GetRequiredService<IOptions<MyApiSettings>>();
client.BaseAddress = settings.Value.ApiRoot;
})
.ConfigurePrimaryHttpMessageHandler(() =>
{
// Add whatever logic to create the handler here
// Similar to the other method, this also has DI-enabled overloads.
var proxy = new WebProxy
{
Address = new Uri("http://test.com:1234"),
BypassProxyOnLocal = false,
UseDefaultCredentials = false,
};
// Create a client handler that uses the proxy
var httpClientHandler = new HttpClientHandler { Proxy = proxy };
// Disable SSL verification
httpClientHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
return httpClientHandler;
});
This will automatically link the configured HttpClient
instance with your MyApiClient
in the container, so that you can then directly inject HttpClient
in the MyApiClient
constructor like in your first example:
public class MyApiClient : IMyApiClient
{
private readonly HttpClient _httpClient;
public MyApiClient(HttpClient httpClient)
{
// It will work now ;)
_httpClient = httpClient;
}
}