使用 Flurl 设置默认的 Polly 策略
Set a default Polly policy with Flurl
我目前同时使用 Polly 和 Flurl,但我有一个必须添加到每个请求的通用重试策略。我注意到 Polly 允许您使用 AddPolicyHandler(...) 设置默认值,但这需要 IHttpClientBuilder 并且我看不到任何从 Flurl 获取它的方法。
我认为重载 DefaultHttpClientFactory 可能是可行的方法,但这只能让我访问 HttpClient,而不是 IHttpClientBuilder。
我知道我可以制作自己的 HttpClient 并将它们传递给 Flurl,但如果可以的话我宁愿避免这样做,因为我希望 Flurl 管理它们的生命周期。
目前有没有办法做我想做的事?
好问题。 Flurl 为您提供了执行此操作所需的所有钩子。首先定义一个采用 Polly 策略的 DelegatingHandler
:
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);
}
}
然后创建一个自定义 IHttpClientFactory
,returns 您的自定义处理程序使用默认处理程序作为其 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()
};
}
}
最后,在应用程序启动时,定义您的策略并使用 Flurl 注册它:
var policy = Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.RetryAsync(5);
FlurlHttp.Configure(settings => settings.HttpClientFactory = new PollyFactory(policy));
一个重要的注意事项是此方法不适用于处理 FlurlHttpException 的策略。那是因为您在此处拦截 HttpMessageHandler
级别的呼叫。 Flurl 将响应和错误转换为堆栈更高的 FlurlHttpException
,因此使用这种方法不会得到 trapped/retried。上面示例中的策略陷阱 HttpRequestException
和 HttpResponseMessage
(具有非 2XX 状态代码),这将起作用。
我目前同时使用 Polly 和 Flurl,但我有一个必须添加到每个请求的通用重试策略。我注意到 Polly 允许您使用 AddPolicyHandler(...) 设置默认值,但这需要 IHttpClientBuilder 并且我看不到任何从 Flurl 获取它的方法。
我认为重载 DefaultHttpClientFactory 可能是可行的方法,但这只能让我访问 HttpClient,而不是 IHttpClientBuilder。
我知道我可以制作自己的 HttpClient 并将它们传递给 Flurl,但如果可以的话我宁愿避免这样做,因为我希望 Flurl 管理它们的生命周期。
目前有没有办法做我想做的事?
好问题。 Flurl 为您提供了执行此操作所需的所有钩子。首先定义一个采用 Polly 策略的 DelegatingHandler
:
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);
}
}
然后创建一个自定义 IHttpClientFactory
,returns 您的自定义处理程序使用默认处理程序作为其 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()
};
}
}
最后,在应用程序启动时,定义您的策略并使用 Flurl 注册它:
var policy = Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.RetryAsync(5);
FlurlHttp.Configure(settings => settings.HttpClientFactory = new PollyFactory(policy));
一个重要的注意事项是此方法不适用于处理 FlurlHttpException 的策略。那是因为您在此处拦截 HttpMessageHandler
级别的呼叫。 Flurl 将响应和错误转换为堆栈更高的 FlurlHttpException
,因此使用这种方法不会得到 trapped/retried。上面示例中的策略陷阱 HttpRequestException
和 HttpResponseMessage
(具有非 2XX 状态代码),这将起作用。