我从一个web API调用中接收到一个响应流,需要将它反序列化为一个模型。
这是一个泛型方法,所以我不能说代码的哪些部分将使用这个方法以及响应负载是什么。
方法如下:
public async Task<T> InvokeAsync<T>(string method)
{
Stream response = await this.httpClientWrapper.InvokeAsync(method);
var serializer = new JsonSerializer();
using var streamReader = new StreamReader(response);
using var reader = new JsonTextReader(streamReader);
return serializer.Deserialize<T>(reader);
}
我正在尝试删除Newtonsoft并使用System.Text.Json API。
我在Github的corefx repo中找到了这个porting guide,其中section阅读from a Stream/String声明:
我们目前(从.NET Core 3.0预览版2开始)没有一个方便的API直接从流中读取JSON(同步或异步)。对于同步阅读(特别是小负载),您可以将JSON负载读取到流的末尾,并将其传递到读取器中
因此,根据这个建议,我得出以下结论:
public async Task<T> InvokeAsync<T>(string method)
{
Stream response = await this.httpClientWrapper.InvokeAsync(method);
var length = response.Length;
var buffer = ArrayPool<byte>.Shared.Rent((int)length);
var memory = new Memory<byte>(buffer);
await response.WriteAsync(memory);
var result = JsonSerializer.Deserialize<T>(memory.Span);
ArrayPool<byte>.Shared.Return(buffer);
return result;
}
所以我的问题是-我是否正确地理解了建议,这是要走的路?
这个实现可能在很多方面都可以改进,但最让我烦恼的是从池中租用字节数组,例如Stream.Length
是一个long,我将其转换为int,这可能导致OverflowException
。
我试着研究System.IO.Pipelines并使用ReadOnlySequence<byte>
重载JSON API,但它变得非常复杂。
2条答案
按热度按时间toe950271#
我认为文档需要更新,因为.NET Core 3有一个直接从流中读取的方法。使用它是直接的,假设流是用UTF8编码的:
需要注意的一点是,默认情况下,HttpClient将在返回之前在内存中缓冲响应内容,除非您在调用SendAsync时将HttpCompletionOption设置为ResponseHeadersRead:
jm81lzqq2#
从ASP.NET Core 6开始,您应该使用 DeserializeAsyncEnumerable() 方法: