JToken.WriteToAsync 没有正确写入流

JToken.WriteToAsync dosen't write to stream correctly

我想将 JToken 异步写入流。我提到了 。 但是,流输出是?[],而ToString()输出是[]。为什么流的开头包含额外的字节?

我的代码如下:

static async Task Main(string[] args)
{
    JArray arr = new JArray();

    //var c = JToken.FromObject("abc");
    //arr.Add(c);

    var stream = new MemoryStream();

    await using (var requestWriter = new StreamWriter(stream, System.Text.Encoding.UTF8, leaveOpen: true))
    {
        var jsonWriter = new JsonTextWriter(requestWriter); 
        try
        {
            await arr.WriteToAsync(jsonWriter);
        }
        finally
        {
            await jsonWriter.CloseAsync();
        }
        Console.WriteLine(System.Text.Encoding.UTF8.GetString(stream.GetBuffer(), 0, checked((int)stream.Length)));

        Console.WriteLine(arr.ToString());

    }
}

为什么流输出不正确? Json.net 的版本是 13.0.1.

总结

您的问题与异步写入无关。你的问题是 Encoding.UTF8:

returns a UTF8Encoding object that provides a Unicode byte order mark (BOM).

您看到的额外 ? 是 BOM。为防止写入 BOM,使用 new UTF8Encoding(false) when writing. Or, you could just do new StreamWriter(stream, leaveOpen: true) as the StreamWriter constructors 将默认使用 UTF-8 编码而不使用字节顺序标记 (BOM)

详情

您的问题可以更简单地重现如下:

JArray arr = new JArray();

var stream = new MemoryStream();

using (var requestWriter = new StreamWriter(stream, System.Text.Encoding.UTF8, leaveOpen: true))
using (var jsonWriter = new JsonTextWriter(requestWriter))
{
    arr.WriteTo(jsonWriter);
}

var resultJson = Encoding.UTF8.GetString(stream.GetBuffer(), 0, checked((int)stream.Length));
Console.WriteLine(BitConverter.ToString(stream.GetBuffer(), 0, checked((int)stream.Length)));
Console.WriteLine(resultJson);
Console.WriteLine(arr.ToString());

Assert.AreEqual(arr.ToString(), resultJson);

断言失败并显示以下消息:

NUnit.Framework.AssertionException:   Expected string length 2 but was 3. Strings differ at index 0.

并使用 BitConverter.ToString() 的以下输出:

EF-BB-BF-5B-5D

演示 fiddle here.

5B-5D是括号,但是EF-BB-BF这三个前导字符是什么?快速搜索显示它是 UTF-8 byte order mark. Since RFC 8259 指定 实现不得在网络传输的 JSON 文本 [=56] 的开头添加字节顺序标记 (U+FEFF) =] 您应该使用 new UTF8Encoding(false) 省略 BOM。因此你的代码应该是这样的:

JArray arr = new JArray();

var stream = new MemoryStream();

await using (var requestWriter = new StreamWriter(stream, new UTF8Encoding(false), leaveOpen: true))
{
    var jsonWriter = new JsonTextWriter(requestWriter); 
    try
    {
        await arr.WriteToAsync(jsonWriter);
    }
    finally
    {
        await jsonWriter.CloseAsync();
    }
}

var resultJson = Encoding.UTF8.GetString(stream.GetBuffer(), 0, checked((int)stream.Length));
Console.WriteLine(BitConverter.ToString(stream.GetBuffer(), 0, checked((int)stream.Length)));
Console.WriteLine(resultJson);
Console.WriteLine(arr.ToString());

Assert.AreEqual(arr.ToString(), resultJson);

演示 fiddle #2 here.