ees*_*ein 4 c# httpresponse flurl polly
目前我有这个要求:
await url
.SetQueryParams(queryString)
.SetClaimsToken()
.GetJsonAsync<T>()
Run Code Online (Sandbox Code Playgroud)
我现在想开始使用Polly(https://github.com/App-vNext/Polly)来处理重试并提供更好的用户体验.例如,由于网络连接不良,第一次尝试时不会"挂断"用户.这是我尝试使用的示例:
int[] httpStatusCodesWorthRetrying = { 408, 500, 502, 503, 504 };
Policy
.Handle<HttpException>()
.OrResult<HttpResponse>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
.WaitAndRetryAsync(new[] {
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
})
.ExecuteAsync( await url... )
Run Code Online (Sandbox Code Playgroud)
但它需要HttpResponse是返回类型.正如你从我的Flurl例子中看到的那样,它正在返回T,即使它是一个HttpResponse.这T只是用于反序列化的类型StringContent.
第一个例子根本不起作用,因为我在PCL中使用它并且我无法获得对它的引用System.Web.所以我尝试了这个:
Policy
.HandleResult(HttpStatusCode.InternalServerError)
.OrResult(HttpStatusCode.BadGateway)
.OrResult(HttpStatusCode.BadRequest)
.WaitAndRetryAsync(new[] {
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
})
.ExecuteAsync(async () =>
{
await url...
});
Run Code Online (Sandbox Code Playgroud)
但是这个也不起作用,因为Polly期望HttpStatusCode作为回归类型.所以我的问题是:我如何告诉polly处理那些HttpStatusCode并仍允许我返回类型T?
Tod*_*ier 14
您不应该使用方便的方法,例如GetJsonAsync<T>(),因为Flurl会对非2XX响应(或者您配置它)引发异常,这应该允许它与Polly非常好地玩.只需删除原始代码中的.Handle<HttpException>和.OrResult<HttpResponse>部分,然后处理FlurlHttpException:
T poco = await Policy
.Handle<FlurlHttpException>(ex => httpStatusCodesWorthRetrying.Contains((int)ex.Call.Response.StatusCode))
.WaitAndRetryAsync(...)
.ExecuteAsync(() => url
.SetQueryParams(queryString)
.SetClaimsToken()
.GetJsonAsync<T>());
Run Code Online (Sandbox Code Playgroud)
并且只是建议进一步清理它:
T poco = await Policy
.Handle<FlurlHttpException>(IsWorthRetrying)
.WaitAndRetryAsync(...)
.ExecuteAsync(() => url
.SetQueryParams(queryString)
.SetClaimsToken()
.GetJsonAsync<T>());
private bool IsWorthRetrying(FlurlHttpException ex) {
switch ((int)ex.Call.Response.StatusCode) {
case 408:
case 500:
case 502:
case 504:
return true;
default:
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
Polly可以将通过策略执行的委托返回的任何值解释为错误.但是,正如您所观察到的,.GetJsonAsync<T>()在您发布的示例中的调用:
await url
.SetQueryParams(queryString)
.SetClaimsToken()
.GetJsonAsync<T>()
Run Code Online (Sandbox Code Playgroud)
正在恢复T.HttpResponseMessage通过直接进入Json反序列化来隐藏调用T.
你需要在flurl中使用一个重载的东西HttpResponseMessage.我没有使用过flurl,但这种超载返回Task<HttpResponseMessage>看起来很有希望.您可以做以下事情:
List<int> httpStatusCodesWorthRetrying = new List<int>(new[] {408, 500, 502, 503, 504});
HttpResponseMessage response = await Policy
.Handle<HttpRequestException>()
.Or<OtherExceptions>() // add other exceptions if you find your call may throw them, eg FlurlHttpException
.OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains((int)r.StatusCode))
.WaitAndRetryAsync(new[] {
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
})
.ExecuteAsync(() =>
url
.SetQueryParams(queryString)
.SetClaimsToken()
.GetAsync()
);
T responseAsT = await Task.FromResult(response).ReceiveJson<T>();
Run Code Online (Sandbox Code Playgroud)
要在通话.ReceiveJson<T>()结束时,建议简单地比较flurl源代码,原来的通话.GetJsonAsync<T>() 这里与取代的.GetAsync(); 位置.
当然你可以把它全部包装成flurl上的一个简洁的扩展helper方法,也许是这样的:
async T GetJsonAsyncResiliently<T>(this IFlurlClient client, Policy policy) // OR (if preferred): this Url url instead of IFlurlClient client
{
return await Task.FromResult(policy.ExecuteAsync(() => client.GetAsync())).ReceiveJson<T>();
}
Run Code Online (Sandbox Code Playgroud)
编辑:我可能指向你的情况下错误的flurl重载,指向方法IFlurlClient.然而,一组平行的扩展方法上flurl内存在Url和string,因此应用相同的原理.
小智 5
通过设置可以使用 Polly 配置的 来配置 FlurlHttpClientFactory并创建自定义HttpClientFactory:
public class MyCustomHttpClientFactory : DefaultHttpClientFactory, IMyCustomHttpClientFactory
{
private readonly HttpClient _httpClient;
public MyCustomHttpClientFactory(HttpClient httpClient)
{
_httpClient = httpClient;
}
public override HttpClient CreateHttpClient(HttpMessageHandler handler)
{
return _httpClient;
}
}
Run Code Online (Sandbox Code Playgroud)
将该服务注册到ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services
.AddHttpClient<IMyCustomHttpClientFactory, MyCustomHttpClientFactory>()
.SetHandlerLifetime(...)
.AddPolicyHandler(....);
}
Run Code Online (Sandbox Code Playgroud)
并将该 Factory 分配给 Flul:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Get HttpClientFactory and Configure Flurl to use it.
var factory = (IMyCustomHttpClientFactory)app.ApplicationServices.GetService(typeof(IMyCustomHttpClientFactory));
FlurlHttp.Configure((settings) => settings.HttpClientFactory = factory);
}
Run Code Online (Sandbox Code Playgroud)