
我的序列化基于以下事实:.NET数据集可以将其架构和数据导出到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());
它失败了
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);
我想念什么?
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.
无法提升作者的状态说明了为什么尝试写入后续内容时会引发异常.
话虽如此,您正在转换器中创建许多不必要的中间字符串,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>继承,在ReadJson()中直接构造了DataSet类型的对象.但是,如reference source所示,JsonConverter T.CanConvert(Type objectType)也适用于类型T的所有子类:
public sealed override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
因此,您可能需要重写CanConvert并使其仅在对象类型等于typeof(DataSet)时才适用-但由于方法已被密封,因此您不能这样做.因此,可能证明有必要从非通用基类JsonConverter继承.
转载注明原文:c#-状态为Property的令牌PropertyName将导致无效的JSON对象.使用自定义JsonConverter时 - 乐贴网