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
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:
Construct an XDocument
and write the DataSet
directly to it using XContainer.CreateWriter();
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
{
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:
You are inheriting from JsonConverterDataSet
directly. However, as shown in the reference source, JsonConverter
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.