I'm trying to make some request via the FlurlClient
to some websites.
But I need to chain some methods that I wrote in a factory.
I use this approach to create the Proxy
and AllowAutoRedirect
factory.
AllowAutoRedirect Extension:
public static IFlurlClient AllowAutoRedirect(this IFlurlClient fc, bool allowAutoRedirect)
{
fc.Settings.HttpClientFactory = new CustomFlurlHttpClientFactory(allowAutoRedirect);
return fc;
}
Proxy Extension :
public static IFlurlClient Proxy(this IFlurlClient fc, DML.Proxy proxy)
{
fc.Settings.HttpClientFactory = new CustomFlurlHttpClientFactory(proxy);
return fc;
}
And finally this are my factory methods
private Proxy _proxy;
private bool? _allowAutoRedirect;
public CustomFlurlHttpClientFactory(Proxy proxy)
{
_proxy = proxy;
}
public CustomFlurlHttpClientFactory (bool? allowAutoRedirect)
{
_allowAutoRedirect = allowAutoRedirect;
}
public override HttpClient CreateHttpClient(HttpMessageHandler handler)
{
return base.CreateHttpClient(handler);
}
public override HttpMessageHandler CreateMessageHandler()
{
if(_proxy != null)
return ProxyClientHandlerConfiguration();
if (_allowAutoRedirect != null)
return AutoRedirectClientHandlerConfiguration();
return base.CreateMessageHandler();
}
private HttpClientHandler AutoRedirectClientHandlerConfiguration() => new HttpClientHandler { AllowAutoRedirect = _allowAutoRedirect ?? true };
private HttpClientHandler ProxyClientHandlerConfiguration() =>
new HttpClientHandler {
Proxy = new WebProxy {
Address = _proxy.GetFullUri(),
BypassProxyOnLocal = true,
UseDefaultCredentials = _proxy.UseDefaultCredentials()
},
UseProxy = true
};
But when the client is created, only the second method executes correctly (Proxy).
I understand that when I call AllowAutoRedirect
, it returns a new HttpClientHandler
, and when Proxy
gets called, it overrides the HttClientHandler
returned by AllowAutoRedirect
var cli = new FlurlClient(url)
.WithHeaders(headers)
.WithCookies(cookies)
.AllowAutoRedirect(false) /*Custom Factory Method*/
.Proxy(proxy) /*Custom Factory Method*/
.EnableCookies();
So, how can I get only one HttpClientHandler
using both methods, AllowAutoRedirect
and Proxy
?
The problem here is that your extension methods are overwriting the existing factory with a new one every time, so the last one will always "win". You need to edit the custom factory (if it exists), not replace it. Start making the factory editable. Something like this:
public class CustomHttpClientFactory : DefaultHttpClientFactory
{
public bool? AutoRedirect { get; set; }
public Proxy Proxy { get; set; }
public override HttpMessageHandler CreateMessageHandler()
{
var handler = new HttpClientHandler();
if (AutoRedirect != null)
handler.AllowAutoRedirect = AutoRedirect;
if (Proxy != null) {
handler.Proxy = new WebProxy { ... };
handler.UseProxy = true;
}
return handler;
}
}
Then your extension methods should look something like this:
public static IFlurlClient AllowAutoRedirect(this IFlurlClient fc, bool allowAutoRedirect)
{
var fac = fc.Settings.HttpClientFactory as CustomHttpClientFactory ??
new CustomHttpClientFactory();
fac.AutoRedirect = allowAutoRedirect;
fc.Settings.HttpClientFactory = fac;
return fc;
}
public static IFlurlClient Proxy(this IFlurlClient fc, Proxy proxy)
{
var fac = fc.Settings.HttpClientFactory as CustomHttpClientFactory ??
new CustomHttpClientFactory();
fac.Proxy = proxy;
fc.Settings.HttpClientFactory = fac;
return fc;
}
Note that you could end up with race conditions if you hit those extension methods for the same FlurlClient
from different threads. But since they're about configuring a client and not a request, hopefully you're just doing that once (per client) and it's not an issue.