Question

I have scoured the Net for info on this, but most of the results are about creating WCF services or situations where the service is under your control.

I am building a WCF client proxy for a RESTful JSON service which is out of my control. I am using the basic ServiceContract/DataContract pattern, and trying to let the framework do as much of the work as possible.

Mostly this is working fine, but all the datetime fields coming from this external service are in a particular format, e.g.

{"SomeObject": 
    {"details":"blue and round", "lastmodified":"2013/01/02 23:14:55 +0000"}
}

So I get an error:

There was an error deserializing the object of type MyNamespace.SomeObject. DateTime content '2013/01/02 23:14:55 +0000' does not start with '/Date(' and end with ')/' as required for JSON.'.

My datacontract is:

namespace Marshmallow.WebServices.ServiceModels
{
    [DataContract]
    public class SomeObject
    {
        [DataMember(Name = "details")]
        public string Details { get; set; }

        [DataMember(Name = "lastmodified")]
        public DateTime LastModified { get; set; }
    }
}

My servicecontract is:

[ServiceContract]
public interface ICoolExternalApi
{
    [OperationContract]
    [WebGet(UriTemplate = "/something.json",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.Wrapped)]
    [return: MessageParameter(Name = "SomeObject")]
    SomeObject GetAccount();
}

What I want to know is, where can I stick some code to define how WCF should deserialize the lastmodified field (make a DateTime object out of the string)?

Or better yet, define how to deserialize all DateTime DataMembers for all my DataContracts. I do not want a lot of repeated code.

I also do not want to resort to some third-party deserializer nor do I want to start putting everything else through a custom deserialization method, if it is avoidable.

Was it helpful?

Solution 2

So far this is the best I have come up with:

I have an internal string Extension method:

internal static class DeserializationHelper
{
    internal static DateTime GetDeserializedDateTime(this string @string)
    {
        if (string.IsNullOrEmpty(@string)) return default(DateTime);
        //insert complex custom deserialization logic here
        return DateTime.Parse(@string);
    }

}

This is the DataMember setup:

[DataMember(Name = "lastmodified")]
internal string _LastModified 
{
    set { LastModified = value.GetDeserializedDateTime(); }
    //getter is not needed for receiving data but WCF requires one
    get { return default(string); }
}

public DateTime LastModified { get; private set; }

If you wanted to use this DataContract for sending data (make this a writeable Property), you would have to write a DateTime Extension method (GetSerializedDateString), expand the setters/getters and introduce private members as go-betweens.

It smells of cut and paste, and it does not take advantage of any WCF framework features. What would Bill Gates do?

OTHER TIPS

Two things I can think of:

  1. Change LastModified to be a string and then convert it to a Datetime object yourself. It would mean exposing two properties for the same data on your object though.
  2. Write a IDispatchMessageInspector to intercept the message before the deserialization occurs and massage the raw message using regex. It would allow a one stop solution for all dates in your service.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top