目前,我有此请求:

await url
    .SetQueryParams(queryString)
    .SetClaimsToken()
    .GetJsonAsync<T>()

我现在想开始使用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... )

但是,它要求HttpResponse为返回类型。从我的Flurl示例中可以看到,即使它是T,它也会返回HttpResponseT只是用于反序列化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...
    });

但这也行不通,因为Polly希望HttpStatusCode作为返回类型。所以我的问题是:如何告诉波莉处理那些HttpStatusCode并仍然允许我返回T类型?

最佳答案

Polly可以将通过策略执行的委托(delegate)返回的任何值解释为错误。但是,正如您观察到的那样,在您发布的示例中对.GetJsonAsync<T>()的调用是:

await url
    .SetQueryParams(queryString)
    .SetClaimsToken()
    .GetJsonAsync<T>()

正在返回T。该调用通过直接将Json反序列化为HttpResponseMessage来隐藏T

您需要在flurl中使用重载,该重载会返回HttpResponseMessage周围的内容。我还没有使用flurl,但是this overload返回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>();

建议仅在最后调用.ReceiveJson<T>()时,将原始调用.GetJsonAsync<T>() here的flurl源代码与替换后的.GetAsync(); here比较即可。

当然,您可以将其全部包装到flurl上的简洁扩展帮助器方法中,也许是这样的:
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>();
}

编辑:在指向IFlurlClient上的方法时,我可能已经指出了错误的flurl重载。但是,在Urlstring上的flurl中存在一组并行的扩展方法,因此适用相同的原理。

关于c# - 如何在Flurl.Http中使用Polly?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40745809/

10-12 02:10