使用Json.NET自定义转换器序列化含DataSet对象时JSON无效错误排查
你的问题出在DataSetConverter的WriteJson方法里使用了writer.WriteRaw()——这个方法会直接把序列化后的XML转JSON字符串原封不动输出,完全忽略了JsonWriter当前的状态。当你序列化包含DataSet的TestClass对象时,JsonWriter正处于写入属性值的状态(正在处理Inserts属性),直接用WriteRaw输出完整的JSON结构会破坏整个JSON的语法,导致你看到的错误。
修复方案
把WriteRaw替换为正确的序列化方式:先将XNode序列化为JToken,再让JsonSerializer来处理这个JToken,这样它会自动适配当前的JSON结构上下文。
修正后的DataSetConverter代码如下:
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); memoryStream.Seek(0, SeekOrigin.Begin); using (StreamReader reader = new StreamReader(memoryStream)) { XDocument document = XDocument.Parse(reader.ReadToEnd()); // 替换WriteRaw为JToken序列化,让JsonWriter正确处理嵌套结构 JToken token = JsonConvert.SerializeXNode(document, Formatting.Indented, false); serializer.Serialize(writer, token); } } } }
为什么原来的写法不行?
当你单独序列化DataSet时,JsonWriter处于根节点状态,直接用WriteRaw输出完整的JSON对象是没问题的;但当序列化TestClass时,JsonWriter正在处理Inserts这个属性,需要输出的是该属性对应的值——而WriteRaw直接输出了一个完整的JSON对象(带{}),这会导致JsonWriter的状态逻辑冲突:它原本在准备写入属性值,突然收到了一个完整的对象结构,自然会抛出"Token PropertyName in state Property would result in an invalid JSON object"的错误。
用serializer.Serialize(writer, token)的话,JsonWriter会根据当前状态正确处理这个JToken,确保嵌套结构的语法完全合规。
验证修复
修改后,你再序列化TestClass对象:
TestClass testClass = new TestClass { Inserts = originalInserts, SomethingElse = "Me" }; string json = JsonConvert.SerializeObject(testClass, Formatting.Indented, new DataSetConverter()); // 反序列化也能正常工作 TestClass deserialized = JsonConvert.DeserializeObject<TestClass>(json, new DataSetConverter());
就不会再出现错误了。
内容的提问来源于stack exchange,提问作者Martin Robins

