如何使用System.Text.Json API将流反序列化到对象 [英] How to deserialize stream to object using System.Text.Json APIs

查看:246
本文介绍了如何使用System.Text.Json API将流反序列化到对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从Web api调用中接收到作为流的响应,需要将其反序列化为模型.

I'm receiving a response from a web api call as a stream and need to deserialize it to a model.

这是一种通用方法,所以我不能说代码的哪一部分将使用此方法,响应有效载荷是什么.

This is a generic method, so I can't say which parts of code will use this and what's the response payload.

这是方法:

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,并使用

I'm trying to remove Newtonsoft and use System.Text.Json API.

我找到了这个移植指南在Github中的corefx存储库中,其中

I found this porting guide in corefx repo in Github, where section Reading from a Stream/String states:

我们目前(从.NET Core 3.0预览版2开始)不方便 直接从流中读取JSON的API(同步或同步) 异步).用于同步阅读(尤其是小 有效负载),您可以读取JSON有效负载,直到流结束 放入字节数组并将其传递给读取器

We currently (as of .NET Core 3.0 preview 2) do not have a convenient API to read JSON from a stream directly (either synchronously or asynchronously). For synchronous reading (especially of small payloads), you could read the JSON payload till the end of the stream into a byte array and pass that into the reader

因此,按照此建议,我提出以下建议:

So following this advise I come up with the following:

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;
}

所以我的问题是-我是否正确理解建议,这是可行的方法?

So my question is - did I understand the advise correctly and this is the way to go ?

此实现可能可以在许多方面进行改进,但是让我最困扰的是从池中租用字节数组,例如Stream.Length是一个长整数,我将其转换为int可能会导致OverflowException.

This implementation probably can be improved on many aspects, but what bothers me most is renting the byte array from the pool e.g. Stream.Length is a long and I convert it to int which can cause OverflowException.

我试图研究系统.IO.Pipelines 并使用JSON API的ReadOnlySequence<byte>重载,但是它变得非常复杂.

I tried to look into System.IO.Pipelines and use ReadOnlySequence<byte> overloads of JSON API, but it gets very complicated.

推荐答案

我相信文档需要更新,因为.NET Core 3具有

I believe that documentation needs to be updated because .NET Core 3 has a method to read from a stream directly. Using it is straight-forward, assuming the stream is encoded in UTF8:

private static readonly JsonSerializerOptions Options = new JsonSerializerOptions();

private static async Task<T> Deserialize<T>(HttpResponseMessage response)
{
    var contentStream = await response.Content.ReadAsStreamAsync();
    var result = await JsonSerializer.DeserializeAsync<T>(contentStream, Options);
    return result;
}

要注意的一件事是,默认情况下,除非在调用SendAsync时将HttpCompletionOption设置为ResponseHeadersRead,否则HttpClient将在返回之前在内存中缓冲响应内容:

One thing to watch out for is that by default HttpClient will buffer the response content in-memory before returning unless you set the HttpCompletionOption to ResponseHeadersRead when invoking SendAsync:

var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token);

这篇关于如何使用System.Text.Json API将流反序列化到对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆