Какой тип сжатия я должен использовать? Или используйте 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
Другие вопросы по тегам