StreamReader的Peek方法是否有异步等效方法?

huangapple go评论78阅读模式
英文:

Is there an async equivalent of StreamReader's Peek method?

问题

我正在将一些netstandard2.0的代码更新,以便不再同步读取HttpRequest.Body(一个Stream)(在netcoreapp3.0中这样做会抛出异常,除非设置AllowSynchronousIO选项,这显然不是一个好主意)。

我已经将JSON反序列化部分转换(使用System.Text.Json),但在进行此操作之前,它会使用StreamReader进行隐秘的.Peek()(以查看正文是对象还是数组),我不太确定在哪里寻找现代的替代方案,该替代方案是异步的,不会消耗Stream

using var reader = new StreamReader(stream);
switch (reader.Peek()) // TODO: 查找一个异步等效的方法!
{
    case '{':
        return await JsonSerializer.DeserializeAsync<GraphQLRequest>(stream);
    case '[':
        return await JsonSerializer.DeserializeAsync<GraphQLRequest[]>(stream);
    default:
        // ...
}
英文:

I'm updating some netstandard2.0 code to not read from the HttpRequest.Body (a Stream) synchronously (this throws exceptions in netcoreapp3.0 unless you set the AllowSynchronousIO option which is obviously not a good idea).

I've converted the JSON deserialization part (to use System.Text.Json), but before it does that it does a sneaky .Peek() using a StreamReader (to see if the body is an object or an array) and I'm not exactly sure where to look for a modern alternative that is asynchronous and won't consume the Stream.

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

答案1

得分: 1

以下是您要翻译的内容:

实际上,Peek 方法首先将流读入其缓冲区,然后从中提供值(请查看dotnet运行时存储库)。因此,它会移动流的位置。然而,不能在不读取和定位流的情况下实现 Peek 功能。

由于无法将 HttpRequestStream 返回到起始位置,更好的策略是读取整个内容,然后使用 Utf8JsonReader 来确定请求是对象还是数组。请注意,Utf8JsonReader 不能在异步方法中声明,因此我不得不将它放在一个单独的非异步方法中。

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:
        // ...
}
英文:

Actually, Peek method reads the stream into its buffer at first and then give you the value from it (take a look at dotnet runtime repo). So it moves the position of a stream. However, peek functionality cannot be implemented without reading and thus seeking the stream.

As you cannot seek HttpRequestStream back, better strategy would be to read the entire content and then use Utf8JsonReader to determine whether the request is an object or an array. Note that Utf8JsonReader cannot be declared in async methods, so I had to put it in a separate non-async method.

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&lt;GraphQLRequest&gt;(jsonBytes);
    case JsonTokenType.StartArray:
        return JsonSerializer.Deserialize&lt;GraphQLRequest[]&gt;(jsonBytes);
    default:
        // ...
}

答案2

得分: 0

在我们由于特殊情况反复考虑后,我们(幸运地!)得到了@davidfowl的帮助,他为我们创建了一个示例,使用了PipeReader和它的AdvanceTo方法来查看令牌但不消耗流,这样我们可以直接从流中使用Deserialize

完整源代码在此

英文:

After going back and forward on this due to our unique circumstances, we (luckily!) got some help from @davidfowl who spun us up an example using PipeReader and it's AdvanceTo method to peek the token but not consume the stream so we could use Deserialize straight from the stream.

Full source here.

huangapple
  • 本文由 发表于 2020年1月7日 02:04:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/59616855.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定