状态 属性 中的令牌 属性Name 将导致无效的 JSON 对象。使用自定义 JsonConverter<T> 时
Token PropertyName in state Property would result in an invalid JSON object. when using custom JsonConverter<T>
我正在尝试 serialise/deserialise 使用 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 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());
失败
Token PropertyName in state Property would result in an invalid JSON
object. Path ''.
我也试过用 JsonConverter
属性装饰 TestClass
上的 DataSet
并从 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));
WriteRawValue()
的 documentation 状态:
Writes raw JSON where a value is expected and updates the writer's state.
而 documentation WriteRaw()
指出:
Writes raw JSON without changing the writer's state.
无法推进作者的状态解释了为什么在尝试写入后续内容时抛出异常。
也就是说,您正在转换器中创建一个 lot 不必要的中间 string
、Stream
和 JObject
表示。一个更简单的方法是,在 WriteJson()
到:
构造一个XDocument
并使用XContainer.CreateWriter()
直接将DataSet
写入其中;
通过构造本地XmlNodeConverter
.
直接将XDocument
序列化为传入的JsonWriter
序列化将遵循相反的过程。因此你的 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;
}
}
备注:
你继承自JsonConverter<DataSet>
, and in ReadJson()
you construct an object of type DataSet
directly. However, as shown in the reference source,JsonConverter<T>.CanConvert(Type objectType)
适用于所有subclasses类型T
还有:
public sealed override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
因此您可能需要重写 CanConvert
并使其仅在对象类型等于 typeof(DataSet)
时应用——但由于该方法已被密封,您不能。因此,可能证明有必要从非泛型基础 class JsonConverter
继承。
我正在尝试 serialise/deserialise 使用 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 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());
失败
Token PropertyName in state Property would result in an invalid JSON object. Path ''.
我也试过用 JsonConverter
属性装饰 TestClass
上的 DataSet
并从 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));
WriteRawValue()
的 documentation 状态:
Writes raw JSON where a value is expected and updates the writer's state.
而 documentation WriteRaw()
指出:
Writes raw JSON without changing the writer's state.
无法推进作者的状态解释了为什么在尝试写入后续内容时抛出异常。
也就是说,您正在转换器中创建一个 lot 不必要的中间 string
、Stream
和 JObject
表示。一个更简单的方法是,在 WriteJson()
到:
构造一个
XDocument
并使用XContainer.CreateWriter()
直接将DataSet
写入其中;通过构造本地
XmlNodeConverter
. 直接将
XDocument
序列化为传入的JsonWriter
序列化将遵循相反的过程。因此你的 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;
}
}
备注:
你继承自
JsonConverter<DataSet>
, and inReadJson()
you construct an object of typeDataSet
directly. However, as shown in the reference source,JsonConverter<T>.CanConvert(Type objectType)
适用于所有subclasses类型T
还有:public sealed override bool CanConvert(Type objectType) { return typeof(T).IsAssignableFrom(objectType); }
因此您可能需要重写
CanConvert
并使其仅在对象类型等于typeof(DataSet)
时应用——但由于该方法已被密封,您不能。因此,可能证明有必要从非泛型基础 classJsonConverter
继承。