0

I'm trying to read a JSON object which contains the date/time in a format that cannot be directly parsed by .NET's DateTime structure. In order to avoid having an 'int' field in my structure for the date/time, I wrote a custom DateTimeConverter:

public class DateTimeConverter : JavaScriptConverter {
  public override IEnumerable<Type> SupportedTypes {
    get { return new Type[] { typeof(DateTime), typeof(DateTime?) }; }
  }

  public override IDictionary<string, object> Serialize(
    object obj, JavaScriptSerializer serializer
  ) { throw new NotImplementedException(); }

  public override object Deserialize(
    IDictionary<string, object> dictionary, Type type,
    JavaScriptSerializer serializer
  ) {
    return DateTime.Now;
  }
}

But when I read a JSON string with the JavaScriptSerializer, it does not use my custom converter:

public struct TextAndDate {
  public string Text;
  public DateTime Date;
}

static void Main() {
  string json =
    "{" +
    "  \"text\": \"hello\", " +
    "  \"date\": \"1276692024\"" +
    "}";

  var serializer = new JavaScriptSerializer();
  serializer.RegisterConverters(new [] { new DateTimeConverter() });
  var test = serializer.Deserialize<TextAndDate>(json);
}

The converter is used when I directly deserialize a DateTime value, just not when I deserialize a type containing a DateTime value.

Why? Any way around this without writing a custom DateTime type or using int?

Cygon
  • 9,444
  • 8
  • 42
  • 50
  • I'm guessing simply: it already found a match in the inbuilt handlers... hence isn't looking for more. – Marc Gravell Jun 23 '10 at 19:25
  • No that's not it. If I deserialize a DateTime directly, my custom converter is used. Also, see MSDN: "Multiple converters can be registered with the same JavaScriptSerializer instance, and these converters can indicate support for the same type. As a result, the last converter that is registered for a specific type is the one that will be used by JavaScriptSerializer to serialize the type." – Cygon Jun 24 '10 at 09:29

1 Answers1

0

You should make small changes in your DateTimeConverter class:

public class DateTimeConverter : JavaScriptConverter {
    public override IEnumerable<Type> SupportedTypes {
        get { return new Type[] { typeof (TextAndDate) }; }
    }

    public override IDictionary<string, object> Serialize (
        object obj, JavaScriptSerializer serializer
    ) { throw new NotImplementedException (); }

    public override object Deserialize (
        IDictionary<string, object> dictionary, Type type,
        JavaScriptSerializer serializer
    ) {
        if (type == typeof (TextAndDate)) {
            TextAndDate td = new TextAndDate ();
            if (dictionary.ContainsKey ("text"))
                td.Text = serializer.ConvertToType<string> (
                                            dictionary["text"]);
            //if (dictionary.ContainsKey ("date"))
                td.Date = DateTime.Now;
            return td;
        }
        else
            return null;
    }
}

UPDATED based on comment: It seems to me that you should use Message Inspectors technique (see http://msdn.microsoft.com/en-us/library/aa717047.aspx). Look at How to ignore timezone of DateTime in .NET WCF client? for an example.

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • Thanks, but while registering my converter for the 'TextAndDate' type itself might work, I would then have to write a custom Converter for each root JSON type returned by the REST API. In the converters, I would also have to associate all fields by hand (as you do in your example) or reimplement the automatic field association normally done by the JavaScriptSerializer. – Cygon Jun 24 '10 at 09:34