Потоковая передача Json - 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 ответ

Ваш код сервера, кажется, в порядке. Однако ваш клиентский код не может нормально взаимодействовать с сервером.

Если вы хотите установить вход 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), вы также можете использовать client.PostAsJsonAsync (url, dto), который находится в пространстве имен HttpClientExtensions, если вы импортируете System.Net.Http.Formatting.dll.

Другие вопросы по тегам