Существует ли asyn c эквивалент метода Peek StreamReader? - PullRequest
4 голосов
/ 06 января 2020

Я обновляю некоторый код netstandard2.0, чтобы он не читался из HttpRequest.Body (a Stream) синхронно (это вызывает исключения в netcoreapp3.0, если вы не установите опцию AllowSynchronousIO, которая, очевидно, не является хорошей идеей ).

Я преобразовал часть десериализации JSON (чтобы использовать System.Text.Json), но перед этим он делает подлый .Peek(), используя StreamReader (чтобы увидеть, является ли тело объект или массив), и я не совсем уверен, где искать современную альтернативу, которая является асинхронной и не потребляет Stream.

using var reader = new StreamReader(stream);
switch (reader.Peek()) // TODO: Find an async equivalent!
{
    case '{':
        return await JsonSerializer.DeserializeAsync<GraphQLRequest>(stream);
    case '[':
        return await JsonSerializer.DeserializeAsync<GraphQLRequest[]>(stream);
    default:
        // ...
}

Ответы [ 2 ]

1 голос
/ 07 января 2020

На самом деле, метод Peek сначала читает поток в его буфер, а затем выдает из него значение (взгляните на do tnet runtime repo ). Таким образом, он перемещает положение потока. Однако функциональность просмотра не может быть реализована без чтения и, следовательно, поиска потока.

Поскольку вы не можете искать HttpRequestStream назад, лучшей стратегией было бы прочитать весь контент, а затем использовать Utf8JsonReader, чтобы определить, является ли запрос объект или массив. Обратите внимание, что Utf8JsonReader нельзя объявить в асинхронных c методах, поэтому мне пришлось поместить его в отдельный не асинхронный c метод.

private static JsonTokenType GetTokenType(byte[] bytes)
{
    var reader = new Utf8JsonReader(bytes.AsSpan());
    reader.Read();
    return reader.TokenType;
}
var ms = new MemoryStream();
await Request.Body.CopyToAsync(ms);
var jsonBytes = ms.ToArray();

switch (GetTokenType(jsonBytes)) 
{
    case JsonTokenType.StartObject:
        return JsonSerializer.Deserialize<GraphQLRequest>(jsonBytes);
    case JsonTokenType.StartArray:
        return JsonSerializer.Deserialize<GraphQLRequest[]>(jsonBytes);
    default:
        // ...
}
0 голосов
/ 21 января 2020

Обратившись вперед и назад в этом из-за наших уникальных обстоятельств, мы (к счастью!) Получили некоторую помощь от @davidfowl, который ускорил наш пример, используя PipeReader и это AdvanceTo метод для просмотра токена, но не потребления поток, чтобы мы могли использовать Deserialize прямо из потока.

Полный источник здесь .

...