5

I'm using Newtonsoft JSON to serialize a DataSet to binary JSON using the code below. When de-serializing back to a DataSet, the field type changes from a Decimal to a Double? Does anybody know what's going wrong?

Sample code:

static void Main(string[] args)
{
  var ds = new DataSet();
  var dt = ds.Tables.Add();
  dt.Columns.Add("Test", typeof(Decimal));
  dt.Rows.Add(new object[] { 1.23345M });

  var data = DataSetToBinJSON(ds);

  var ds2 = BinJSONToDataSet(data);
  Console.WriteLine((ds2.Tables[0].Columns[0].DataType == typeof(Decimal)) ? "Passed" : string.Format("Failed- {0}", ds2.Tables[0].Columns[0].DataType));
  Console.ReadLine();
}



/// <summary>
/// Utility function to create an optimized Binary JSON version of a DataSet
/// </summary>
public static byte[] DataSetToBinJSON(DataSet dataSet)
{
  if (dataSet == null || dataSet.Tables == null || dataSet.Tables.Count == 0)
  {
    return null;
  }

  using (var ms = new MemoryStream())
  {
    using (var writer = new BsonWriter(ms))
    {
      var serializer = new JsonSerializer();
      serializer.Serialize(writer, dataSet);
      return ms.ToArray();
    }
  }
}


/// <summary>
/// Utility function to deserialize an optimized Binary JSON serialized DataSet
/// </summary>   
public static DataSet BinJSONToDataSet(byte[] dataBytes)
{
  if (dataBytes.Length == 0)
  {
    return null;
  }

  using (var ms = new MemoryStream(dataBytes))
  {
    using (var reader = new BsonReader(ms))
    {
      var serializer = new JsonSerializer();
      return serializer.Deserialize<DataSet>(reader);
    }
  }
}
Keith Blows
  • 1,580
  • 12
  • 14
  • 1
    It's not a bug, it's normal behavior. Json format does not distinguish between float/double/decimal types, but you can implement own JsonTextReader. Solution: http://stackoverflow.com/a/9916087/835720 – oakio Jul 11 '13 at 19:48
  • 1
    @oakio- many thanks. Figured this out by simply checking the source! Was expecting Newtonsoft serialization to behave like: http://chrish.com.au/blog/json-netdeserializing-a-datatable/. – Keith Blows Jul 11 '13 at 20:02

2 Answers2

5

Easy way to fix this set FloatParseHandling = FloatParseHandling.Decimal

Example:

    public class Foo
    {
        public object Value { get; set; }
    }

    Foo original = new Foo
        {
            Value = 1.23m
        };

    string json = JsonConvert.SerializeObject(original);

    var settings = new JsonSerializerSettings
        {
            FloatParseHandling = FloatParseHandling.Decimal //hint
        };
    Foo actual = JsonConvert.DeserializeObject<Foo>(json, settings);

    // actual.Value.GetType() == 'Decimal'
oakio
  • 1,868
  • 1
  • 14
  • 21
  • Oakio. Your comment on the question was the answer, so I'm accepting the answer on this response. This is interesting, but not what I'm looking for. I was looking for 100% lossless DataSet Binary Json serialization, but it turned out I can do with the simple serialization. – Keith Blows Jul 13 '13 at 11:30
0

I suspect it has something to do with the standard (XML) serialization of DataSet and DataTable.

If you write DataSet from the example to a file you'll see that information about the DataTable schema isn't provided. This can be determined when reading the XML file back into a table.

The data from your example written to a file gives this result:

<NewDataSet>
  <Table1>
    <Test>1.23345</Test>
  </Table1>
</NewDataSet>

When the DataSet with the DataTable has been read you can't change the type of the column (in my test case when going to/from XML the type is string) but you can .Clone() the DataTable and move/convert the data:

var clonedTable = ds.Tables[0].Clone();
clonedTable.Columns[0].DataType = typeof(decimal);
foreach (DataRow row in dt.Tables[0].Rows) {
    clonedTable.ImportRow(row);
}
Michael Banzon
  • 4,879
  • 1
  • 26
  • 28
  • Hi thanks, but this is Binary JSON, not XML? The conversion done by Newtonsoft uses its own DataSet JSON format, not the Microsoft XML standard. However, you are right that the JSON produced is similar to the XML (with no types) you provided: {"Table1":[{"Test":1.23345}]} – Keith Blows Jul 11 '13 at 17:42
  • Please ignore the above comment. I was under the impression the conversion done by Newtonsoft used its own DataSet JSON format, not the standard serialization. I was relying on 100% lossless DataSet conversion, but I guess that is not possible. – Keith Blows Jul 11 '13 at 17:49
  • Simply looking at the source, https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Converters/DataTableConverter.cs, clearly reveals any non-integer gets converted to a double. – Keith Blows Jul 11 '13 at 19:57