小编典典

使用JSON.NET将对象序列化为HttpClient的响应流

json

抽象

嗨,我正在一个项目中,需要通过HttpClient发送某个对象的潜在巨大json,典型大小是10-20
mb的JSON。为了有效地做到这一点,我想使用流,两者都通过Json.Net来序列化一个对象,另外还要使用流来使用HttpClient发布数据。

问题

这是使用Json.net进行序列化的代码段,为了使用流,Json.net希望它将写入其中:

public static void Serialize( object value, Stream writeOnlyStream )
{
    StreamWriter writer = new StreamWriter(writeOnlyStream);  <-- Here Json.net expects the stream to be already created
    JsonTextWriter jsonWriter = new JsonTextWriter(writer);
    JsonSerializer ser = new JsonSerializer();
    ser.Serialize(jsonWriter, value );
    jsonWriter.Flush();
}

虽然HttpClient期望从中读取的流:

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://localhost:54359/");

    var response = await client.PostAsync("/api/snapshot", new StreamContent(readOnlyStream)); <-- The same thing here, HttpClient expects the stream already to exist

    ... 
}

因此,最终这意味着这两个类都期望Stream由其他人创建,但是Json.Net和HttpClient都没有流。因此,似乎可以通过实现一个流来解决该问题,该流将拦截对只读流的读取请求,并根据来自只写流的请求发出写入。

也许已经有人偶然发现了这种情况,并且可能已经找到解决该问题的方法。如果是这样,请与我分享,

先感谢您!


阅读 298

收藏
2020-07-27

共1个答案

小编典典

使用PushStreamContent。与其让Web API从流中“拉”,不如让它更直观地“推入”其中。

object value = ...;

PushStreamContent content = new PushStreamContent((stream, httpContent, transportContext) =>
{
    using (var tw = new StreamWriter(stream))
    {
        JsonSerializer ser = new JsonSerializer();
        ser.Serialize(tw, value);
    }
});

请注意,JSON.NET在序列化过程中不支持异步,因此虽然这可能会提高内存效率,但是扩展性却不高。

不过,我建议您尝试避免使用如此大的JSON对象。例如,如果您要通过一个大集合发送邮件,请尝试对其进行分块。如果没有特殊处理,许多客户/服务器都会拒绝这么大的东西。

2020-07-27