Troopers
Troopers

Reputation: 5452

Why IsoDateTimeConverter is not used to serialize Dictionary<DateTime, int>

The result of a webAPI method that return a Dictionary is not serialized with the format defined in IsoDateTimeConverter

This is my configuration:

public static class WebApiConfig
{
    //Web API configuration and services
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
        config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter
        {
            DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff'Z'"
        });
    }
}

Here a sample of webAPI method

[Route("GetPlanning")]
[HttpPost]
public Dictionary<DateTime, IEnumerable<int>> GetPlanning()
{
    Dictionary<DateTime, IEnumerable<int>> planning = new Dictionary<DateTime,IEnumerable<int>>();
    planning.Add(DateTime.UtcNow, new List<int>(){0,1,2});
    return planning;
}

In client side the result is an object with a property that is a date without the millisecond.

If i return a array : return planning.ToArray(); the result is an array of object key value with a date with millisecond.

So why the format is apllied on a date in a array and not in a dictionary?

Upvotes: 0

Views: 1483

Answers (1)

dbc
dbc

Reputation: 117275

The reason IsoDateTimeConverter is not used for dictionary keys is that Json.NET does not serialize the keys - it merely converts them to strings. From the docs:

When serializing a dictionary, the keys of the dictionary are converted to strings and used as the JSON object property names. The string written for a key can be customized by either overriding ToString() for the key type or by implementing a TypeConverter. A TypeConverter will also support converting a custom string back again when deserializing a dictionary.

Thus converters, including IsoDateTimeConverter, are not used when converting dictionary keys to JSON.

That being said, IsoDateTimeConverter is no longer necessary. From Serializing Dates in JSON

From Json.NET 4.5 and onward dates are written using the ISO 8601 format by default, and using this converter is unnecessary.

The same date formatting can be obtained by setting JsonSerializerSettings.DateFormatString:

config.Formatters.JsonFormatter.SerializerSettings.DateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff'Z'";

But how does this affect dictionary key conversion to JSON? As it turns out, Json.NET does respect this setting when converting a DateTime to a string as a dictionary key, as shown in the reference source. Thus:

var time = DateTime.Now;

Dictionary<DateTime, IEnumerable<int>> planning = new Dictionary<DateTime, IEnumerable<int>>();
planning.Add(DateTime.UtcNow, new List<int>() { 0, 1, 2 });
var root = new { today = time, planning = planning };

var settings = new JsonSerializerSettings
{
    DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc,
    DateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff'Z'",
};
var json = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Console.WriteLine(json);

Produces the required output with consistent formatting for a DateTime value used as a dictionary keys and used as a property:

{
  "today": "2016-09-09T03:54:51.704Z",
  "planning": {
    "2016-09-09T03:54:51.704Z": [
      0,
      1,
      2
    ]
  }
}

Upvotes: 3

Related Questions