Beware of WCF POST service methods that receive JSON that contain DateTime values

I ran into a weird problem today… I have a third party that returns some data to our endpoint in JSON format.

I created my endpoint, posted JSON to it, and all seemed well. But when the third party posted it, the service returned Http 400, Bad Request. Turns out the third party was seeing this:

The server encountered an error processing the request. The exception message is ‘There was an error deserializing the object of type ReturnService.ResponseStructure. DateTime content ‘2016-10-26 13:02:38’ does not start with ‘\/Date(‘ and end with ‘)\/’ as required for JSON.’. See server logs for more details.

So far, I had been working with JSON that I serialized and deserialized myself using JavaScriptSerializer. However, when creating a service method to do the deserializing for me, the WCF service uses something else based on a JSON spec older than ISO8601, and expects the dates to be in a very different format. Since this behaviour happens before it even hits my code, it’s rather annoying.

The hacky solution I used was to treat the dates as strings, ironically something I always advise everybody not to do. Then use DateTime.TryParseExact to get the actual dates.

That is, my service method and the class for the JSON is now declared like this:

using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace ExampleService
{
    [ServiceContract]
    public interface IExampleReturnService
    {
        [OperationContract]
        [WebInvoke(UriTemplate = "/PostJSONExample",
            Method = "POST",
            RequestFormat = WebMessageFormat.Json)]
        void PostJSONExample(ResponseStructure request);
    }

    #region JSON structure

    [DataContract]
    public class record
    {
        [DataMember]
        public string text { get; set; }

        [DataMember]
        public string timestamp { get; set; }

        [DataMember]
        public int pairedMessageId { get; set; }

        [DataMember]
        public string receiver { get; set; }
    }

    [DataContract]
    public class data
    {
        [DataMember]
        public record[] record { get; set; }
    }

    [DataContract]
    public class ResponseStructure
    {
        [DataMember]
        public data data { get; set; }
    }

    #endregion
}

And the implementation, with only the code relevant to parsing the date, is this:

    public class ExampleReturnService : IExampleReturnService
    {
        public void PostJSONExample(ResponseStructure request)
        {
            foreach (record r in request.data.record)
            {
                DateTime responseDate;
                if (DateTime.TryParseExact(
                    r.timestamp, 
                    "yyyy-MM-dd HH:mm:ss", 
                    CultureInfo.InvariantCulture, 
                    DateTimeStyles.AdjustToUniversal, out responseDate))
                {
                    DateTime date = responseDate.ToLocalTime();
                    // Do something with date...
                }
            }
        }
    }
Advertisements

About Jerome

I am a senior C# developer in Johannesburg, South Africa. I am also a recovering addict, who spent nearly eight years using methamphetamine. I write on my recovery blog about my lessons learned and sometimes give advice to others who have made similar mistakes, often from my viewpoint as an atheist, and I also write some C# programming articles on my programming blog.
This entry was posted in Programming and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s