状态 Property 中的令牌 PropertyName 将导致无效的 JSON 对象。使用自定义 JsonConverter

2023-11-23

我正在尝试使用 Json.NET 和自定义序列化程序序列化/反序列化 .NET 数据集。我知道你们中的许多人会告诉我不要这样做(我在其他帖子上看到过这一点)我有充分的理由并希望继续沿着这条路走。

我的序列化基于以下事实:.NET DataSet 可以将其架构和数据导出到 XML,然后重新导入相同的内容;在此基础上,我尝试创建一个转换器,允许我捕获 XML、将其转换为 JSON,然后将其转换回来并重新加载。我的实现如下...

class DataSetConverter : JsonConverter<DataSet>
{
    public override DataSet ReadJson(JsonReader reader, Type objectType, DataSet existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        DataSet dataSet = new DataSet();
        JObject jObject = JObject.Load(reader);

        String json = jObject.ToString();
        XDocument document = JsonConvert.DeserializeXNode(json);
        using (MemoryStream memoryStream = new MemoryStream())
        using (StreamWriter streamWriter = new StreamWriter(memoryStream))
        {
            streamWriter.Write(document.ToString(SaveOptions.None));
            streamWriter.Flush();

            memoryStream.Position = 0;
            dataSet.ReadXml(memoryStream);
        }

        return dataSet;
    }

    public override void WriteJson(JsonWriter writer, DataSet dataSet, JsonSerializer serializer)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            dataSet.WriteXml(memoryStream, XmlWriteMode.WriteSchema);
            using (StreamReader reader = new StreamReader(memoryStream))
            {
                memoryStream.Seek(0, SeekOrigin.Begin);
                XDocument document = XDocument.Parse(reader.ReadToEnd());
                writer.WriteRaw(JsonConvert.SerializeXNode(document, Formatting.Indented, false));
            }
        }
    }
}

如下使用(纯粹序列化 DataSet 对象)它可以工作(我的新 DataSet 具有与原始 DataSet 相同的架构和数据)...

DataSet originalInserts = new DataSet("Inserts");
DataTable originalStuff = originalInserts.Tables.Add("Stuff");

originalStuff.Columns.Add("C1", typeof(String));
originalStuff.Columns.Add("C2", typeof(Int64));
originalStuff.Columns.Add("C3", typeof(Guid));
originalStuff.Columns.Add("C4", typeof(float));

originalStuff.Rows.Add("One", 2, Guid.NewGuid(), 4.4);

String json = JsonConvert.SerializeObject(originalInserts, Formatting.Indented, new DataSetConverter());

DataSet newInsertsFromConvertedXml = (DataSet)JsonConvert.DeserializeObject(json, typeof(DataSet), new DataSetConverter());

但是,如果我随后尝试对包含以下内容的对象使用相同的转换器DataSet(完全相同的DataSet如上)...

public class TestClass
{
    public DataSet Inserts { get; set; }

    public String SomethingElse { get; set; }
}

TestClass testClass = new TestClass { Inserts = originalInserts, SomethingElse = "Me" };
json = JsonConvert.SerializeObject(testClass, Formatting.Indented, new DataSetConverter());

它失败了

状态属性中的令牌 PropertyName 将导致无效的 JSON 目的。小路 ''。

我也尝试过装饰DataSet on the TestClass with a JsonConverter属性并从 Serialize 方法调用中删除转换器,但得到相同的结果......

public class TestClass
{
    [JsonConverter(typeof(DataSetConverter))]
    public DataSet Inserts { get; set; }

    public String SomethingElse { get; set; }
}

TestClass testClass = new TestClass { Inserts = originalInserts, SomethingElse = "Me" };
json = JsonConvert.SerializeObject(testClass, Formatting.Indented);

我缺少什么?


你的基本问题是你应该打电话WriteRawValue()代替WriteRaw():

writer.WriteRawValue(JsonConvert.SerializeXNode(document, Formatting.Indented, false)); 

The 文档 for WriteRawValue() states:

在需要值的地方写入原始 JSON 并更新写入器的状态。

鉴于文档 WriteRaw() states:

写入原始 JSON 而不更改写入器的状态。

未能推进写入器的状态解释了为什么在尝试写入后续内容时会引发异常。

话虽如此,您正在创建一个lot不必要的中间string, Stream and JObject转换器内的表示。一个更简单的方法是,在WriteJson() to:

  1. 构建一个XDocument并写下DataSet直接使用它XContainer.CreateWriter();

  2. 序列化XDocument直接进入传入的JsonWriter通过构建一个本地XmlNodeConverter.

序列化将遵循相反的过程。因此你的DataSetConverter看起来像:

class DataSetConverter : JsonConverter<DataSet>
{
    public override DataSet ReadJson(JsonReader reader, Type objectType, DataSet existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        if (reader.MoveToContent().TokenType == JsonToken.Null)
            return null;
        var converter = new XmlNodeConverter { OmitRootObject = false };
        var document = (XDocument)converter.ReadJson(reader, typeof(XDocument), existingValue, serializer);
        using (var xmlReader = document.CreateReader())
        {
            var dataSet = existingValue ?? new DataSet();
            dataSet.ReadXml(xmlReader);
            return dataSet;
        }
    }

    public override void WriteJson(JsonWriter writer, DataSet dataSet, JsonSerializer serializer)
    {
        var document = new XDocument();
        using (var xmlWriter = document.CreateWriter())
        {
            dataSet.WriteXml(xmlWriter, XmlWriteMode.WriteSchema);
        }
        var converter = new XmlNodeConverter { OmitRootObject = false };
        converter.WriteJson(writer, document, serializer);
    }
}

public static partial class JsonExtensions
{
    public static JsonReader MoveToContent(this JsonReader reader)
    {
        // Start up the reader if not already reading, and skip comments
        if (reader.TokenType == JsonToken.None)
            reader.Read();
        while (reader.TokenType == JsonToken.Comment && reader.Read())
            {}
        return reader;
    }
}

Notes:

  1. 你继承自JsonConverter<DataSet>,并在ReadJson()你构造一个类型的对象DataSet直接地。然而,如图所示参考来源, JsonConverter<T>.CanConvert(Type objectType)适用于所有子类类型的T also:

    public sealed override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }
    

    因此你可能需要覆盖CanConvert并使其仅在对象类型等于时适用typeof(DataSet)——但是由于该方法已被密封,所以你不能。因此,可能需要从非泛型基类继承JsonConverter反而。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

状态 Property 中的令牌 PropertyName 将导致无效的 JSON 对象。使用自定义 JsonConverter 时 的相关文章

  • 删除文件的最后 10 个字符

    我想删除文件的最后 10 个字符 说一个字符串 hello i am a c learner 是文件内的数据 我只是希望该文件是 hello i am a 文件的最后 10 个字符 即字符串 c learner 应在文件内消除 解决方案 将
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • 如何获取 EF 中与组合(键/值)列表匹配的记录?

    我有一个数据库表 其中包含每个用户 年份组合的记录 如何使用 EF 和用户 ID 年份组合列表从数据库获取数据 组合示例 UserId Year 1 2015 1 2016 1 2018 12 2016 12 2019 3 2015 91
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • LINQ:使用 INNER JOIN、Group 和 SUM

    我正在尝试使用 LINQ 执行以下 SQL 最接近的是执行交叉联接和总和计算 我知道必须有更好的方法来编写它 所以我向堆栈团队寻求帮助 SELECT T1 Column1 T1 Column2 SUM T3 Column1 AS Amoun
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐