views:

65

answers:

2

I am experiencing issues with a WCF REST service. The wire object that I try to return has certain properties not set, resulting in DateTime.MinValue for properties of type DateTime. The service returns an empty document (with HTTP status 200 ???). When I try to call JSON serialization myself, the exception that is thrown is:

SerializationException: DateTime values that are greater than DateTime.MaxValue or smaller than DateTime.MinValue when converted to UTC cannot be serialized to JSON.

This can be reproduced by running the following code in a console app:

DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(DateTime));
MemoryStream m = new MemoryStream();
DateTime dt = DateTime.MinValue;

// throws SerializationException in my timezone
ser.WriteObject(m, dt);
string json = Encoding.ASCII.GetString(m.GetBuffer());
Console.WriteLine(json);

Why is this behaviour? I think it is related to my timezone (GMT+1). As DateTime.MinValue is default(DateTime), I would expect that this can be serialized without problems.

Any tips on how to make my REST service behave? I don't want to change my DataContract.

+3  A: 

If your time zone is GMT+1, then the UTC value of DateTime.MinValue in your time zone is going to be an hour less than DateTime.MinValue.

Adam Robinson
Yes, I figured as much. But what to do? Isn't it weird that the default value of a very common class from the framework cannot be serialized in one half of the world?
Teun D
+2  A: 

The main problem is DateTime.MinValue has DateTimeKind.Unspecified kind. It defined as:

MinValue = new DateTime(0L, DateTimeKind.Unspecified);

But this is not real problem, this definition leads to problem during serialization. JSON DateTime serialization done thru:

System.Runtime.Serialization.Json.JsonWriterDelegator.WriteDateTime(DateTime value)

Unfortunately it defined as:

...

if (value.Kind != DateTimeKind.Utc)
{
    long num = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks;
    if ((num > DateTime.MaxValue.Ticks) || (num < DateTime.MinValue.Ticks))
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString("JsonDateTimeOutOfRange"), new ArgumentOutOfRangeException("value")));
    }
}

...

So it does'nt take into account Unspecified and treats it as Local. To avoid this situation you can define your own constant:

MinValueUtc = new DateTime(0L, DateTimeKind.Utc);

or

MinValueUtc = DateTime.MinValue.ToUniversalTime();

It looks weird of cause, but it helps.

Nick Martyshchenko
That is a nice explanation. This also explains why XML serialization works and JSON doesn't. My problem is that the MinValue is there because it is not set. Instead of adding a simple attribute, I will now have to set this custom MinValueUtc to all datetime properties.
Teun D
You may consider working (or just store) with datetimes always in UTC converting to LocalTime just before you need to show them. So after init either in constructor or just in proper setter convert 'incoming' datetime value to UTC via .ToUniversalTime(). It helps resolve default value problem.
Nick Martyshchenko