I have Asp.Net Core WebApi
. I am making Http requests according to HttpClientFactory pattern. Here is my sample code:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpClient<IMyInterface, MyService>();
...
}
public class MyService: IMyInterface
{
private readonly HttpClient _client;
public MyService(HttpClient client)
{
_client = client;
}
public async Task CallHttpEndpoint()
{
var request = new HttpRequestMessage(HttpMethod.Get, "www.customUrl.com");
var response = await _client.SendAsync(request);
...
}
}
I want to implement sending requests through dynamic proxy. This basically means that I might need to change proxy with each request. As for now I find out 2 approuces, non of which seems good to me:
1.Have a static proxy like this:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpClient<IMyInterface, MyService>().ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler
{
Proxy = new WebProxy("http://127.0.0.1:8888"),
UseProxy = true
};
});
...
}
But I can only have single proxy per service in this approach.
2.Dispose HttpClient
with each request:
HttpClientHandler handler = new HttpClientHandler()
{
Proxy = new WebProxy("http://127.0.0.1:8888"),
UseProxy = true,
};
using(var client = new HttpClient(handler))
{
var request = new HttpRequestMessage(HttpMethod.Get, "www.customUrl.com");
var response = await client.SendAsync(request);
...
}
But in this way I violate HttpClientFactory pattern and it might cause issues to application performance as stated in following article
Is there a third way where I could change proxy dinamically without re-creating HttpClient
?
答案 0 :(得分:3)
There is no way to change the any of the properties of HttpClientHandler
or to assign a new version of HttpClientHandler
to an existing HttpClient
after it is instantiated. As such, it is then impossible to have a dynamic proxy for a particular HttpClient
: you can only specify one proxy.
The correct way to achieve this is to use named clients, instead, and define a client for each proxy endpoint. Then, you'll need to inject IHttpClientFactory
and pick one of the proxies to use, requesting the named client that implements that.
services.AddHttpClient("MyServiceProxy1").ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler
{
Proxy = new WebProxy("http://127.0.0.1:8888"),
UseProxy = true
};
});
services.AddHttpClient("MyServiceProxy2").ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler
{
Proxy = new WebProxy("http://127.0.0.1:8889"),
UseProxy = true
};
});
...
Then:
public class MyService : IMyInterface
{
private readonly HttpClient _client;
public MyService(IHttpClientFactory httpClientFactory)
{
_client = httpClientFactory.CreateClient("MyServiceProxy1");
}
public async Task CallHttpEndpoint()
{
var request = new HttpRequestMessage(HttpMethod.Get, "www.customUrl.com");
var response = await _client.SendAsync(request);
...
}
}
答案 1 :(得分:0)
我可以通过从HttpClientHandler继承来做到这一点:
public class ProxyHttpHandler : HttpClientHandler
{
private int currentProxyIndex = 0;
private ProxyOptions proxyOptions;
public ProxyHttpHandler(IOptions<ProxyOptions> options)
{
proxyOptions = options != null ? options.Value : throw new ArgumentNullException(nameof(options));
UseProxy = true;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var proxy = proxyOptions.Proxies[currentProxyIndex];
var proxyResolver = new WebProxy(proxy.Host, proxy.Port)
{
Credentials = proxy.Credentials
};
Proxy = proxyResolver;
currentProxyIndex++;
if(currentProxyIndex >= proxyOptions.Proxies.Count)
currentProxyIndex = 0;
return base.SendAsync(request, cancellationToken);
}
}
然后我在IoC中注册ProxyHttpHandler
和ProxyOptions
:
public IForksCoreConfigurationBuilder ConfigureProxy(Action<ProxyOptions> options)
{
Services.AddOptions<ProxyOptions>().Configure(options);
Services.AddTransient<ProxyHttpHandler>();
Services.AddHttpClient<IService, MyService>()
.ConfigurePrimaryHttpMessageHandler<ProxyHttpHandler>();
return this;
}