2016-11-22 1 views
2

В настоящее время у меня есть этот запрос:Как использовать Полли с Flurl.Http?

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, хотя это 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... 
    }); 

Но это один и не работает, потому что Polly ожидает HttpStatusCode в качестве возвращаемого типа. Поэтому мой вопрос: как я могу рассказать polly обрабатывать те HttpStatusCode s и все еще разрешить возврат типа T?

Спасибо!

ответ

3

Полли может интерпретировать любое значение, возвращаемое делегатом, выполненным политикой, в качестве ошибки. Однако, как вы наблюдали, вызов .GetJsonAsync<T>() в вашем публикуемую например:

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

возвращается T. Вызов скрывает HttpResponseMessage, идя прямо к десериализации Json до 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>() в конце предлагается просто сравнивая исходный код flurl для первоначального вызова .GetJsonAsync<T>()here с замещенным .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>(); 
} 

EDIT: Я, возможно, указывает на неправильные flurl перегрузками для вашего случая, в указывая на методы на IFlurlClient. Однако параллельный набор методов расширения существует внутри flurl на Url и string, поэтому применяются те же принципы.

+0

@eestein Сделаны некоторые незначительные изменения синтаксиса после загрузки flurl. Это вас сортирует? –

+0

Спасибо за ваш ответ, сейчас проверим! – eestein

+0

Спасибо, мне удалось адаптировать мой код, используя ваши примеры! :) – eestein

3

Вы не должны ломаться с помощью удобных методов, как GetJsonAsync<T>(), потому что Flurl бросает исключение на не 2xx ответов (или же вы configure это), что должно позволить ему играть очень приятно с Полли.Просто удалите .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>()); 

И только предложение для очистки, что до далее:

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; 
    } 
} 
+0

Прохладный, спасибо Todd :) – eestein

+0

Выглядит хорошо, Тодд! Я тоже задавался вопросом об этом подобном подходе. Я изначально не рекомендовал, поскольку я не был уверен, что все flurl звонки гарантируют возврат «FlurlHttpException». Например, https://github.com/tmenier/Flurl/blob/master/src/Flurl.Http.Shared/FlurlClient.cs#L201 (который является общедоступным) не ловушка? Но согласитесь, что этот шаблон действительно хорош с '.GetJsonAsync ())'. Хорошая библиотека, кстати. –

+0

@mountaintvaleller Если вызов завершен и ответ содержит статус неуспеха, 'FlurlHttpException' гарантируется _virtually_. По крайней мере, это намеченное, задокументированное поведение. Но если это вызывает беспокойство, то, конечно, не помешает сохранить другие конфигурации Polly. (Спасибо, и ваша библиотека тоже выглядит очень милой!) Это дает мне идеи для добавления попыток к Flurl :)) –

Смежные вопросы