英文:
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 '{':
return await JsonSerializer.DeserializeAsync<GraphQLRequest>(stream);
case '[':
return await JsonSerializer.DeserializeAsync<GraphQLRequest[]>(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<GraphQLRequest>(jsonBytes);
case JsonTokenType.StartArray:
return JsonSerializer.Deserialize<GraphQLRequest[]>(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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论