c# - .NET Core JsonDocument.Parse(ReadOnlyMemory, JsonReaderOptions) 无法从 WebSocket ReceiveAsync 解析
问题描述
我使用 .NET Core 3.0JsonDocument.Parse(ReadOnlyMemory<Byte>, JsonReaderOptions)
将 WS 消息 () 解析byte[]
为 JSON,但它会引发如下异常:
'0x00' is invalid after a single JSON value. Expected end of data. LineNumber: 0 | BytePositionInLine: 34.
这是我的中间件代码段:
WebSocket ws = await context.WebSockets.AcceptWebSocketAsync();
byte[] bytes = new byte[1024 * 4];
ArraySegment<byte> buffer = new ArraySegment<byte>(bytes);
while (ws.State == WebSocketState.Open)
{
try
{
WebSocketReceiveResult request = await ws.ReceiveAsync(bytes, CancellationToken.None);
switch (request.MessageType)
{
case WebSocketMessageType.Text:
string msg = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
json = new ReadOnlyMemory<byte>(bytes);
JsonDocument jsonDocument = JsonDocument.Parse(json);
break;
default:
break;
}
}
catch (Exception e)
{
Console.WriteLine($"{e.Message}\r\n{e.StackTrace}");
}
}
解决方案
如评论中所述,您犯了一些错误。最大的问题之一是您分配内存(从长远来看会导致分配和 gc,这是 Memory/Span API 想要避免的)。第二个是,您没有对数据进行切片,因为您的有效负载小于缓冲区大小。
我对代码所做的一些修复
WebSocket ws = await context.WebSockets.AcceptWebSocketAsync();
// Don't do that, it allocates. Beats the main idea of using [ReadOnly]Span/Memory
// byte[] bytes = new byte[1024 * 4];
// We don't need this either, its old API. Websockets support Memory<byte> in an overload
// ArraySegment<byte> buffer = new ArraySegment<byte>(bytes);
// We ask for a buffer from the pool with a size hint of 4kb. This way we avoid small allocations and releases
// P.S. "using" is new syntax for using(disposable) { } which will
// dispose at the end of the method. new in C# 8.0
using IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.Rent(1024 * 4);
while (ws.State == WebSocketState.Open)
{
try
{
ValueWebSocketReceiveResult request = await ws.ReceiveAsync(memory.Memory, CancellationToken.None);
switch (request.MessageType)
{
case WebSocketMessageType.Text:
// we directly work on the rented buffer
string msg = Encoding.UTF8.GetString(memory.Memory.Span);
// here we slice the memory. Keep in mind that this **DO NOT ALLOCATE** new memory, it just slice the existing memory
// reason why it doesnt allocate is, is that Memory<T> is a struct, so its stored on the stack and contains start
// and end position of the sliced array
JsonDocument jsonDocument = JsonDocument.Parse(memory.Memory.Slice(0, request.Count));
break;
default:
break;
}
}
catch (Exception e)
{
Console.WriteLine($"{e.Message}\r\n{e.StackTrace}");
}
}
您需要对其进行切片,因此 Json 解析器不会读取超出 JSON 字符串末尾的内容。
推荐阅读
- go - 如何创建两个列表的地图,其中一个列表又是地图?
- cordova - 即使从最近的列表中删除了phonegap应用程序,如何让它运行?
- typescript - TypeScript 中的类到实例注册表类型
- dart - Flutter中Column的孩子之间的空间
- javascript - 无法从 HTML 的输入框中获取新键入的值
- rxjs - 无法从拦截器订阅数据
- database - Visual Basic BadImageFormatException 错误信息连接到 Oracle 数据库
- cassandra - 如何理解 page_state 只能用于 CQL Paging 中的 SAME 查询
- ios - 如何在 iPhone 上获得持续的 WiFi 强度
- android - 根据 Firebase 中的日期对事件进行排序