Great question. Flurl gives you all the necessary hooks to do this. First define a DelegatingHandler
that takes a Polly policy:
public class PollyHandler : DelegatingHandler
{
private readonly IAsyncPolicy<HttpResponseMessage> _policy;
public PollyHandler(IAsyncPolicy<HttpResponseMessage> policy) {
_policy = policy;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
return _policy.ExecuteAsync(ct => base.SendAsync(request, ct), cancellationToken);
}
}
Then create a custom IHttpClientFactory
that returns your custom handler with the default handler as its InnerHandler
:
public class PollyFactory : DefaultHttpClientFactory
{
private readonly IAsyncPolicy<HttpResponseMessage> _policy;
public PollyFactory(IAsyncPolicy<HttpResponseMessage> policy) {
_policy = policy;
}
public override HttpMessageHandler CreateMessageHandler() {
return new PollyHandler(_policy) {
InnerHandler = base.CreateMessageHandler()
};
}
}
Finally, on app startup, define your policy and register it with Flurl:
var policy = Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.RetryAsync(5);
FlurlHttp.Configure(settings => settings.HttpClientFactory = new PollyFactory(policy));
One important note is that this approach will not work with a policy that handles FlurlHttpException. That's because you're intercepting calls at the HttpMessageHandler
level here. Flurl converts responses and errors to FlurlHttpException
s higher up the stack, so those won't get trapped/retried with this approach. The policy in the example above traps HttpRequestException
and HttpResponseMessage
(with non-2XX status codes), which will work.