Token PropertyName in state Property would result in an invalid JSON object. when using custom JsonConverter<T>

六眼飞鱼酱① 提交于 2019-12-01 21:14:59

Your basic problem is that you should be calling WriteRawValue() instead of WriteRaw():

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

The documentation for WriteRawValue() states:

Writes raw JSON where a value is expected and updates the writer's state.

Whereas the documentation WriteRaw() states:

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.

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:

  1. Construct an XDocument and write the DataSet directly to it using XContainer.CreateWriter();

  2. Serialize the XDocument directly to the incoming JsonWriter by constructing a local XmlNodeConverter.

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;
    }
}

Notes:

  1. You are inheriting from 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) applies to all subclasses of the type T also:

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

    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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!