状态为Property的令牌PropertyName将导致无效的JSON对象.使用自定义JsonConverter< T>时 [英] Token PropertyName in state Property would result in an invalid JSON object. when using custom JsonConverter<T>
问题描述
我正在尝试使用Json.NET和自定义序列化程序对.NET数据集进行序列化/反序列化.我知道你们中的许多人会告诉我不要(我在其他帖子上也看到过),我有充分的理由,并希望继续沿着这条路线前进.
I am trying to serialise/deserialise a .NET DataSet using Json.NET and a custom serialiser. I know many of you will tell me not to (I have seen this on other posts) I have a valid reason and wish to continue down this route.
我的序列化基于以下事实:.NET数据集可以将其架构和数据导出到XML,然后重新导入.在此基础上,我尝试创建一个转换器,该转换器将允许我捕获该XML,将其转换为JSON,然后将其转换回并重新加载.我的实现如下...
My serialisation is based upon the fact that the .NET DataSet can export it's schema and data to XML and then re-import the same; on that basis, I am trying to create a converter that will allow me to capture that XML, convert it to JSON then convert it back and reload it. My implementation is as follows...
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具有相同的架构和数据)...
Used as follows (purely serialising a DataSet object) it works (my new DataSet has the same schema and data as the original)...
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
)一起使用...
However if I then try and use the same converter with an object that contains a DataSet
(the very same DataSet
as above)...
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());
失败并显示
状态为Property的令牌PropertyName将导致无效的JSON 目的.路径.
Token PropertyName in state Property would result in an invalid JSON object. Path ''.
我还尝试用JsonConverter
属性装饰TestClass
上的DataSet
,并从Serialize方法调用中删除转换器,但得到的结果相同...
I have also tried decorating the DataSet
on the TestClass
with a JsonConverter
attribute and removing the converter from the Serialize method call but get the same result...
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()
:
Your basic problem is that you should be calling WriteRawValue()
instead of WriteRaw()
:
writer.WriteRawValue(JsonConvert.SerializeXNode(document, Formatting.Indented, false));
WriteRawValue()
状态的文档:
在期望值的地方写入原始JSON并更新编写者的状态.
Writes raw JSON where a value is expected and updates the writer's state.
文档 WriteRaw()
指出:
在不更改编写者状态的情况下写入原始JSON.
Writes raw JSON without changing the writer's state.
无法提升作者的状态,这解释了为什么尝试写入后续内容时会引发异常.
The failure to advance the writer's state explains why an exception is thrown when an attempt is made to write subsequent content.
也就是说,您正在创建转换器内部不必要的中间string
,Stream
和JObject
表示形式的 lot .在WriteJson()
中,更简单的方法是:
That being said, you're creating a lot of unnecessary intermediate string
, Stream
and JObject
representations inside your converter. A simpler approach would be, in WriteJson()
to:
-
构造一个
XDocument
并使用DataSet写入到其中. xcontainer.createwriter?view = netframework-4.7.2"rel =" nofollow noreferrer> XContainer.CreateWriter()
;
Construct an
XDocument
and write theDataSet
directly to it usingXContainer.CreateWriter()
;
通过构造本地JsonWriter
nofollow noreferrer> XmlNodeConverter
.
Serialize the XDocument
directly to the incoming JsonWriter
by constructing a local XmlNodeConverter
.
串行化将遵循相反的过程.因此,您的DataSetConverter
看起来像是:
Serialization would follow the reverse process. Thus your DataSetConverter
would look like:
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>
继承,并在ReadJson()
中构造类型为DataSet
的对象直接地.但是,如参考源所示,JsonConverter<T>.CanConvert(Type objectType)
也适用于类型为T
的所有子类:
You are inheriting from
JsonConverter<DataSet>
, and inReadJson()
you construct an object of typeDataSet
directly. However, as shown in the reference source,JsonConverter<T>.CanConvert(Type objectType)
applies to all subclasses of the typeT
also:
public sealed override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
因此,您可能需要覆盖CanConvert
并使其仅在对象类型等于typeof(DataSet)
时才适用-但由于该方法已被密封,因此您不能.因此,可能有必要从非通用基类 JsonConverter
继承代替.
Thus you may need to override CanConvert
and make it apply only when the object type is equal to typeof(DataSet)
-- but since the method has been sealed, you cannot. Therefore, it may prove necessary to inherit from the non-generic base class JsonConverter
instead.
这篇关于状态为Property的令牌PropertyName将导致无效的JSON对象.使用自定义JsonConverter< T>时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!