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