Поток уже был израсходован. Невозможно прочитать ошибку еще раз при использовании Polly для повторных запросов C# .NET 6

Я прочитал эту ошибку «Поток уже использован», используя Polly для повторения запросов в ASP.NET Core, но не вижу, где клонировать сообщение HTTP-запроса.

Итак, в моем коде я регистрирую httpclient следующим образом:

var httpClientBuilder = serviceCollection.AddHttpClient("CustomHttpClientName");
httpClientBuilder.AddHttpMessageHandler(ctx=>...)
httpClientBuilder.AddPolicyHandler(GetRetryPolicy());
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions.HandleTransientHttpError()
        .OrResult(result => !result.IsSuccessStatusCode)
        .OrResult(result =>
        {
            var elem = result.Content.ReadFromJsonAsync<JsonElement>().GetAwaiter().GetResult();
            return elem.TryGetProperty("error", out _);
        })
        .WaitAndRetryAsync(
            sleepDurations: Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 3),
            onRetry: (outcome, timespan, retryCount, context) =>
            {
                context.GetLogger()?.LogWarning("Delaying for {Delay}ms, then making retry {Retry}.", timespan.TotalMilliseconds, retryCount);
            });
}

а затем вызов HTTP-клиента:

var request = CreateRequest(jsonContent, HttpMethod.Post, uri);
await GetClient().SendAsync(request, cancellationToken); // here I get runtime exception

Я хочу повторить попытку, если в ответном json вижу поле error.

Приведенный выше код приводит к исключению InvalidOperationException: «Поток уже использован. Его нельзя прочитать еще раз»

Связано: github.com/App-vNext/Polly/issues/854 ?

Fildor 19.08.2024 16:04

Вы не можете повторно использовать HttpRequestMessage, потому что существует проверка повторного использования . Вам следует заново создавать объект запроса для каждой повторной попытки.

Peter Csala 19.08.2024 16:59

@PeterCsala: проблема не в повторных попытках. Когда запрос будет успешным, код-потребитель захочет прочитать результат, но код проверки ошибок в этой политике уже прочитает из потока.

StriplingWarrior 19.08.2024 17:03

Думайте о ручье как о «спуске» - большинство ручьев не могут снова подняться на холм, чтобы снова спуститься без каких-либо дополнительных усилий - как иногда делает насос на реальном ручье - но тогда действительно ли это тот же самый ручей или новый? поток с одинаковым/похожим содержимым

Mark Schultheiss 19.08.2024 17:07

@StriplingWarrior Извините, я неправильно понял, вы правы.

Peter Csala 19.08.2024 17:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не проверял это, но, возможно, удастся сохранить исходный результат в памяти, пока вы его читаете, вот так:

        .OrResult(result =>
        {
            if (result.Content is not ByteArrayContent)
            {
                var originalContent = result.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
                result.Content = new ByteArrayContent(originalContent);
            }
            var elem = result.Content.ReadFromJsonAsync<JsonElement>().GetAwaiter().GetResult();
            return elem.TryGetProperty("error", out _);
        })

Заменив содержимое копией в памяти, вы разрешите его многократное чтение. Просто имейте в виду, что это меняет некоторые поведения вашего приложения: код-потребитель не будет «завершать» запрос до тех пор, пока не будет прочитан весь ответ. Но если вы ожидаете прочитать ответ в формате JSON, это, вероятно, не имеет большого значения.

Другим возможным способом решения этой проблемы было бы разделение обязанностей. IAsyncPolicy<HttpResponseMessage> может фокусироваться только на самом HTTP-ответе (не обращая внимания на контент). Тогда у вас может быть отдельный служебный класс для получения конкретного типа ответа JSON, который вы ищете, и использовать IAsyncPolicy<JsonElement> для комбинированных действий по получению ответа и чтению из него JSON. Тогда ваш критерий «дескриптора» будет напрямую смотреть на JsonElement, а не пытаться напрямую прочитать JSON из потока контента.

Также обратите внимание, что Polly.Extensions.Http устарел в пользу Microsoft.Extensions.Http.Resilience.

Чем это отличается от Content LoadIntoBufferAsync?

Peter Csala 19.08.2024 18:38

@PeterCsala: Отличный призыв. Я не знал об этом методе. Похоже, это сделает то же самое.

StriplingWarrior 19.08.2024 22:49

Хотя, если честно, я все меньше убеждаюсь в том, что правильно понял первопричину. В ходе простого тестирования мне не удалось воспроизвести сообщенное исключение.

StriplingWarrior 19.08.2024 23:17

Другие вопросы по теме