【问题标题】:JToken.WriteToAsync dosen't write to stream correctlyJToken.WriteToAsync 不能正确写入流
【发布时间】:2021-05-11 12:06:54
【问题描述】:

我想将 JToken 异步写入流。我提到了JToken.WriteToAsync does not write to JsonWriter。 但是,流输出为?[],而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。

【问题讨论】:

  • MemoryStream 用于测试,不用于生产
  • 向该尝试添加一个catch,看看是否有异常。这会对你有很大帮助。
  • 您在StreamWriter requestWriter 被释放之前访问stream。尝试将对 stream.GetBuffer() 的呼叫移至 await using (var requestWriter ... 之外。
  • @tanxin - 除了回答您的问题之外,我还更新了对JToken.WriteToAsync does not write to JsonWriter 的回答,不包括 BOM。

标签: c# json json.net


【解决方案1】:

总结

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

返回一个提供 Unicode 字节顺序标记 (BOM) 的 UTF8Encoding 对象。

您看到的额外? 是该BOM。为防止BOM被写入,写入时使用new UTF8Encoding(false)。或者,您可以只使用new StreamWriter(stream, leaveOpen: true),因为StreamWriter constructors 默认使用不带字节顺序标记 (BOM) 的 UTF-8 编码

详情

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

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

演示小提琴here.

5B-5D 是括号,但是三个前导字符 EF-BB-BF 是什么?快速搜索显示它是UTF-8 byte order mark。由于RFC 8259 指定实现不得在网络传输的 JSON 文本的开头添加字节顺序标记 (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);

演示小提琴#2 here.

【讨论】:

    猜你喜欢
    • 2020-07-09
    • 1970-01-01
    • 2021-11-14
    • 2016-08-22
    • 1970-01-01
    • 2018-08-22
    • 1970-01-01
    • 2011-03-12
    • 1970-01-01
    相关资源
    最近更新 更多