Deserialize data with missing first column

I am trying to serialize a .NET DataTable to a JSON file and then deserialize the JSON file back to a DataTable. I just realized what I think.

However, I have a table, 3 rows of 3 columns, each element is of type double. If any value in the first row is NULL, when JSON.Net deserializes the json file into a DataTable, all the values ​​of the column that was empty in the first row become rows.

To be clear, only if the value in the first line is null, this will happen. If any values ​​are zero on any other row than the first, the remaining values ​​in this column remain doubled.

  • If I replaced null with double, everything will work as expected (I cannot do this in my case, however).

  • If I set NullValueHandling = NullValueHandling.Ignore, all values ​​will be doubled, except that the first line will now be indicated as the last line:

Example:

"Column2": 1.0, "Column3": 1.1 }, { "Column1": 0.0, "Column2": 0.5, "Column3": 2.0 }, 

becomes:

  "Column2": 1.0, "Column3": 1.1 }, { "Column2": 0.5, "Column3": 2.0, "Column1": 0.0 }, 

I need to be able to deserialize JSON, keep the columns in order and not have null values ​​in the first row so that all values ​​in this row become rows. I also need to leave column 1 of the first row (in the case above) null - don't care if it is an empty row or DBNull.

Any thoughts? (My test code is below ..comment / uncomment NullValueHandling to see the problem)

  DataTable table = new DataTable("MyTable"); table.Columns.Add("Column1", typeof(double)); table.Columns.Add("Column2", typeof(double)); table.Columns.Add("Column3", typeof(double)); for (int i = 0; i < 10; i++) { if (i == 0) table.Rows.Add(null, 1.0, 1.1); else table.Rows.Add(0.0, 0.5, 2.0); } JsonSerializer serializer = new JsonSerializer(); //serializer.TypeNameHandling = TypeNameHandling.All; serializer.NullValueHandling = NullValueHandling.Ignore; using (StreamWriter sw1 = new StreamWriter("1st.json")) using (JsonWriter writer1 = new JsonTextWriter(sw1)) { writer1.Formatting = Formatting.Indented; serializer.Serialize(writer1, table); } DataTable newtable; using (StreamReader sr = new StreamReader("1st.json")) using (JsonReader reader = new JsonTextReader(sr)) { newtable = (DataTable)serializer.Deserialize(reader, typeof(DataTable)); } using (StreamWriter sw = new StreamWriter("3rd.json")) using (JsonWriter writer = new JsonTextWriter(sw)) { writer.Formatting = Formatting.Indented; serializer.Serialize(writer, newtable); } 
+1
source share
1 answer

Json.NET is an open source MIT license , so one option would be to create a modified version of the DataTableConverter to suit your needs. Its source code is available here .

First, create your own forked version of this class called, say, JsonDefaultTypeDataTableConverter<T> . Change the GetColumnDataType method to return typeof(T) for the value of the null column:

 /// <summary> /// Converts a <see cref="DataTable"/> to and from JSON. /// Adapted from https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/DataTableConverter.cs /// </summary> public class JsonDefaultTypeDataTableConverter<T> : JsonConverter { private static Type GetColumnDataType(JsonReader reader) { JsonToken tokenType = reader.TokenType; switch (tokenType) { case JsonToken.Integer: case JsonToken.Boolean: case JsonToken.Float: case JsonToken.String: case JsonToken.Date: case JsonToken.Bytes: return reader.ValueType; case JsonToken.Null: case JsonToken.Undefined: return typeof(T); // WAS typeof(string). case JsonToken.StartArray: CheckedRead(reader); if (reader.TokenType == JsonToken.StartObject) { return typeof (DataTable); // nested datatable } Type arrayType = GetColumnDataType(reader); return arrayType.MakeArrayType(); default: throw new JsonSerializationException(string.Format("Unexpected JSON token when reading DataTable: {0}", tokenType)); } } } 

You will also need to fix the calls to throw a JsonSerializationException on line 232 , for example, as follows:

  private static void CheckedRead(JsonReader reader) { if (!reader.Read()) { throw new JsonSerializationException(string.Format("Unexpected end when reading DataTable.")); } } 

And, around line 114 :

  if (reader.TokenType != JsonToken.StartArray) { throw new JsonSerializationException(string.Format("Unexpected JSON token when reading DataTable. Expected StartArray, got {0}.", reader.TokenType)); } 

Now, given that you know that your table contains columns of double values, you can use it as follows:

  JsonSerializer serializer = new JsonSerializer(); //serializer.TypeNameHandling = TypeNameHandling.All; //serializer.NullValueHandling = NullValueHandling.Ignore; -- DO NOT USE THIS OPTION. serializer.Converters.Add(new JsonDefaultTypeDataTableConverter<double>()); 

Please note that you do not change the internals of Json.NET itself, you copy and modify one of your standard standard converters for the widely used .Net types.

Update: full version here .

+1
source

All Articles