我必须使用哪种表达方式?或者将StreamContent与JsonTextWriter一起使用

本文关键字:StreamContent 一起 或者 JsonTextWriter 表达方式 | 更新日期: 2023-09-27 18:27:30

我正在用.NET Framework 4.5、C#和Newtonsoft.Json 6.0.8开发一个ASP.NET Web Api 2.2应用程序。

我有这个方法发布到这个网络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;
}

当我有很多数据要发送时,我会在这里得到内存不足的异常:

HttpContent content = new StringContent(JsonConvert.SerializeObject(dataToPost), Encoding.UTF8, "application/json");

我读了很多关于压缩的书,但我不知道该用哪一本。我不知道是否还有更多的类型,但我发现了两种:IIS压缩和GZip压缩。

我必须用哪一个?如果我使用GZip压缩,我是否必须修改我的web 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,但我不知道如何在我的post方法中使用它。

更新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告诉我,为了提高效率,我需要使用JsonTextWriter将其作为流写入StreamContent

但我不知道该怎么做,因为我不知道如何实例化StreamContent。我看到的所有示例都使用var stream,但我不知道它们是如何实例化该对象的。

如何使用JsonTextWriter写入流?

我必须使用哪种表达方式?或者将StreamContent与JsonTextWriter一起使用

您所说的压缩不会解决您的问题。

它只会在HTTP级别压缩数据。因此,在您的代码中,您仍然会得到相同的解压缩字符串,以及在反序列化过程中发生的相同OutOfMemoryException

您需要更改反序列化JSON的方式。请参阅C#中的增量JSON解析。

编辑:对不起,我读错了。这是序列化,而不是反序列化。不过,同样的问题。序列化本身或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