流式Json - 带有大对象的PushStreamContent

时间:2017-06-02 17:35:01

标签: c# json stream streaming pushstreamcontent

我需要流式传输大型对象。我无法弄清楚如何以块的形式发送它。但是,发布的代码有效, 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);
                        }
                    }
                }
            }

1 个答案:

答案 0 :(得分:0)

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

如果要设置DocumentDto输入,则需要将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),那么您还可以使用在HttpClientExtensions命名空间中的client.PostAsJsonAsync(url,dto)导入系统.Net.Http.Formatting.dll。