【问题标题】:Streaming Json - PushStreamContent with a Large Object流式 Json - 带有大对象的 PushStreamContent
【发布时间】:2017-06-02 17:35:00
【问题描述】:

我需要流式传输一个大对象。我无法弄清楚如何分块发送。发布的代码有效,但是,stream.Flush() 只被调用一次。所以,基本上我正在缓冲对象 - 不好。如何多次调用 stream.Flush()?如果我有一个集合,我可以循环流式传输/刷新。那么我该如何处理大对象呢?

服务器代码:

   public async Task<HttpResponseMessage> ConvertToTiffAsync([FromBody] DocumentDto dto)
                {
                    // THIS IS LARGE
                    var document = await _service.ConvertToTiffAsync(dto);
                    var response = Request.CreateResponse();
                    response.Content = new PushStreamContent((stream, content, context) =>
                    {
                        var serializer = new JsonSerializer();
                        using (var writer = new StreamWriter(stream))
                        {
                            using (var jsonTextWriter = new JsonTextWriter(writer))
                            {
                                serializer.Serialize(jsonTextWriter, document);
                                stream.Flush(); // ONLY CALLED ONCE - NEED MANY CALLS
                            }
                        }
                    });
                    return response;
                }

客户代码(此处未进行流式传输,但需要):

using (var client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
            {
                client.Timeout = new TimeSpan(0, 5, 0);
                var stringContent = new StringContent(JsonConvert.SerializeObject(dto), Encoding.UTF8, "application/json");
                using (var httpRequest = new HttpRequestMessage(HttpMethod.Post, endpoint))
                {
                    httpRequest.Content = stringContent;
                    using (HttpResponseMessage response = await client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
                    {
                        response.EnsureSuccessStatusCode();
                        using (var streamReader = new StreamReader(await response.Content.ReadAsStreamAsync()))
                        using (var jsonReader = new JsonTextReader(streamReader))
                        {
                            var serializer = new JsonSerializer();
                            return await Task.Run(() => serializer.Deserialize<ConvertDocumentDto>(jsonReader)).ConfigureAwait(false);
                        }
                    }
                }
            }

【问题讨论】:

  • 你不需要冲洗。 PushStreamContent 所做的基本上是所有写入它的数据都直接流式传输到客户端而不缓冲内容。那么你确定完整的 JSON 表示在内存中吗?
  • 另外根据thomaslevesque.com/2013/11/30/…,如果你想流式传输 JSON,你可以使用 new ObjectContent(document, new JsonMediaTypeFormatter()) 而不是 PushStreamContent,它应该做同样的事情,但更简洁。
  • @ckuri ...那篇文章的重点是上传而不是下载。此外,在调用 flush() 之前,我不相信数据是流式传输的——至少我在运行代码时是这样看的。
  • 上传和下载的工作方式与在两种情况下都使用 HttpContent 的子类相同。
  • flush 无论如何都无关紧要,因为当您离开 using 块时调用的 StreamWriters Dispose 方法总是调用流 flush 方法。所以这条线是多余的。你到底看到了什么?

标签: c# json stream streaming pushstreamcontent


【解决方案1】:

您的服务器代码似乎没问题。但是,您的客户端代码似乎无法与服务器正确交互。

如果要将 DocumentD 设置为输入,则需要将 JSON 写入请求,而不是响应。如果您想在内存中没有完整 JSON 的情况下使用服务器操作,则需要一个 JsonTextReader。所以一般在客户端应该是:

var client = new HttpClient();
var dtoContent = new PushStreamContent((stream, content, context) => {
   var serializer = new JsonSerializer();
    using (var streamWriter = new StreamWriter(stream))
    {
       using (var jsonWriter = new JsonTextWriter(streamWriter))
       { serializer.Serialize(jsonTextWriter, dto); }
    }
});
using (var stream = await client.PostAsync(url, dtoContent).Content.ReadAsStreamAsync())
{
  using (var streamReader = new StreamReader(stream))
  {
    using (var jsonReader = new JsonTextReader(streamReader))
    {
        document = JsonSerializer().Deserialize<Document>(jsonReader);
    }
  }
}

如果您的 DTO 很小,并且您不介意在内存中使用完整的 JSON 而不是 client.PostAsync(url),如果您导入 System,您还可以使用位于 HttpClientExtensions 命名空间中的 client.PostAsJsonAsync(url, dto) .Net.Http.Formatting.dll。

【讨论】:

  • 对不起,我为客户发布了错误的代码。实际的代码 ID 现在在那里并且不会流式传输。
猜你喜欢
  • 2018-10-08
  • 1970-01-01
  • 2019-07-03
  • 1970-01-01
  • 2023-02-15
  • 1970-01-01
  • 2014-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多