通过RecyclableMemoryStream的Json序列化错误

mu0hgdu0  于 2023-01-06  发布在  其他
关注(0)|答案(1)|浏览(116)

我使用如下代码替换默认的json序列化方法:

private readonly static RecyclableMemoryStreamManager _recyclableMemoryStreamManager = 
    new RecyclableMemoryStreamManager(blockSize: 128 * 1024, largeBufferMultiple: 1024 * 1024, maximumBufferSize: 128 * 1024 * 1024);

private ByteArrayContent Serialize(object content, JsonSerializerSettings serializerSettings, Encoding encoding, string mediaType)
{
    var jsonSerializer = Newtonsoft.Json.JsonSerializer.Create(serializerSettings);
    using (var memoryStream = _recyclableMemoryStreamManager.GetStream())
    {
        using (var textWriter = new StreamWriter(memoryStream, encoding, 1024, true))
        {
            using (var jsonTextWriter = new JsonTextWriter(textWriter) { CloseOutput = false })
            {
                jsonSerializer.Serialize(jsonTextWriter, content);
                jsonTextWriter.Flush();
                var arraySegment = new ArraySegment<byte>(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
                var resContent = new ByteArrayContent(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
                resContent.Headers.ContentType = new MediaTypeHeaderValue(mediaType);
                return resContent;
            }
        }
    }
}

但有时,http响应json与sytanx错误:

{
  "code": 0,
  "msg": null,
  "data": [
    // ....
  ]
}
')","foo":"","bar":"baz","flag":0,')","foo":"","bar":"baz","flag":0,
')","foo":"","bar":"baz","flag":0,')","foo":"","bar":"baz","flag":0,

如何解决这个问题?
我想可能是重复使用缓冲区错误,
也许可以改变RecyclableMemoryStreamManager的值?

_recyclableMemoryStreamManager.AggressiveBufferReturn = true;
pgvzfuti

pgvzfuti1#

来自GetBuffer()的缓冲区仅在流的生存期 * 内定义良好;当方法退出memoryStreamusing块时,您将释放该流,这意味着这些缓冲区现在可供重用。
您可能希望改用StreamContent;这接受有效载荷的Stream,并且在发送时处置它:我会用“that "这会给予你想要的语义。注意:不要自己处理memoryStream-删除那个using(可能添加一个执行memoryStream?.Dispose(); throw;catch块)。
还要注意,GetBuffer() * 不 * 一定是RecyclableMemoryStream的最佳API,因为它可能在内部使用多个不连续的缓冲区;应该有一个ReadOnlySequence<byte> GetReadOnlySequence() API允许这种使用-但是,这仍然具有影响缓冲区重用的相同生命周期限制,因此:也不会改变什么。
未经测试,但供考虑:

private HttpContent Serialize(object content, JsonSerializerSettings serializerSettings, Encoding encoding, string mediaType)
{
    var jsonSerializer = JsonSerializer.Create(serializerSettings);
    var memoryStream = _recyclableMemoryStreamManager.GetStream();
    try
    {
        using (var textWriter = new StreamWriter(memoryStream, encoding, 1024, true))
        {
            using var jsonTextWriter = new JsonTextWriter(textWriter) { CloseOutput = false };
            jsonSerializer.Serialize(jsonTextWriter, content);
            jsonTextWriter.Flush();
        }
        memoryStream.Position = 0; // rewind
        var resContent = new StreamContent(memoryStream);
        resContent.Headers.ContentType = new MediaTypeHeaderValue(mediaType);
        return resContent;
    }
    catch
    {
        memoryStream?.Dispose();
        throw;
    }
}

然而,我希望通过内置JSON媒体编码器直接序列化到输出,而不是使用中间缓冲区。

相关问题