Какой тип сжатия я должен использовать? Или используйте StreamContent с JsonTextWriter
Я занимаюсь разработкой приложения ASP.NET Web Api 2.2 с.NET Framework 4.5, C# и Newtonsoft.Json 6.0.8.
У меня есть этот метод для публикации в этом веб-API:
protected bool Post<T>(string completeUri, ref T dataToPost)
{
bool result = false;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_webApiHost);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpContent content = new StringContent(JsonConvert.SerializeObject(dataToPost), Encoding.UTF8, "application/json");
Task<HttpResponseMessage> response = client.PostAsync(completeUri, content);
[ ... ]
}
return result;
}
Когда у меня много данных для отправки, я получаю исключение Out of Memory:
HttpContent content = new StringContent(JsonConvert.SerializeObject(dataToPost), Encoding.UTF8, "application/json");
Я много читал о сжатии, но я не знаю, какой из них мне нужно использовать. Я не знаю, есть ли другие типы, но я нашел два вида: сжатие IIS и сжатие GZip.
Какой я должен использовать? Если я использую сжатие GZip, нужно ли мне модифицировать мой веб-API-клиент?
ОБНОВИТЬ:
У меня есть этот класс для сериализации, но я не использовал его:
public static string Serialize(Models.Aggregations aggregation)
{
if (aggregation == null)
throw new ArgumentNullException("aggregation");
StringWriter sw = new StringWriter();
JsonTextWriter writer = new JsonTextWriter(sw);
writer.WriteStartObject();
writer.WritePropertyName("Code");
writer.WriteValue(aggregation.Code);
if (!string.IsNullOrWhiteSpace(aggregation.Created))
{
writer.WritePropertyName("Created");
writer.WriteValue(aggregation.Created);
}
writer.WriteEndObject();
return sw.ToString();
}
Это решит проблему, если я буду ее использовать? Я спрашиваю об этом, потому что @CodeCaster предложил мне использовать JsonTextWriter
но я не знаю, как использовать его в моем методе записи.
ОБНОВЛЕНИЕ 2
Следуя рекомендации @CodeCaster, я пытаюсь оптимизировать способ отправки данных на этот Web Api и пишу свой собственный сериализатор JSON с этим классом:
public static string Serialize(Models.Aggregations aggregation)
{
if (aggregation == null)
throw new ArgumentNullException("aggregation");
StringWriter sw = new StringWriter();
JsonTextWriter writer = new JsonTextWriter(sw);
writer.WriteStartObject();
writer.WritePropertyName("Code");
writer.WriteValue(aggregation.Code);
if (!string.IsNullOrWhiteSpace(aggregation.Created))
{
writer.WritePropertyName("Created");
writer.WriteValue(aggregation.Created);
}
writer.WriteEndObject();
return sw.ToString();
}
Но @CodeCaster сказал мне, что для того, чтобы сделать его более эффективным, мне нужно написать в виде потока в StreamContent
с помощью JsonTextWriter
,
Но я не знаю, как это сделать, потому что я не знаю, как создать экземпляр StreamContent
, Все примеры, которые я видел, используют var stream
но я не вижу, как они создают этот объект.
Как я могу использовать JsonTextWriter для записи в поток?
2 ответа
Сжатие, о котором вы говорите, не решит вашу проблему.
Он будет сжимать данные только на уровне HTTP. Таким образом, в вашем коде вы все равно получите ту же распакованную строку и ту же OutOfMemoryException
который происходит во время десериализации.
Вам нужно изменить способ десериализации JSON. См. Инкрементальный анализ JSON в C#.
Редактировать: извините, я прочитал совершенно неправильно. Это сериализация, а не десериализация. Тем не менее, тот же вопрос. Либо сама сериализация, либо создание экземпляра StringContent
бросает это исключение. Вам нужно сериализовать его в потоковом режиме и напрямую транслировать на выход.
Итак: используйте StreamContent
не StringContent
и использовать JsonTextWriter
записать в поток. Таким образом, вам не нужно иметь всю сериализованную строку в памяти.
Дано results
как IEnumerable<T>
содержащий ваши объекты, вы можете использовать JsonTextWriter для записи в ответ OutputStream следующим образом:
// get the response output stream ..
using (StreamWriter stream = new StreamWriter(HttpContext.Current.Response.OutputStream))
using (JsonTextWriter writer = new JsonTextWriter(stream))
{
// .. and use json.net to write the data as json in the stream
var serializer = new JsonSerializer();
serializer.Serialize(writer, results);
}
Если у вас есть свой JsonSerializer
Вы можете легко подключить его.
Содержание ответа будет сжато и разделено на части. Быстро и аккуратно
Response Headers
Transfer-Encoding: chunked
Content-Type: application/json
Content-Encoding: gzip