views:

128

answers:

2

Is it possible to override the default WCF DataContractSerializer behaviour when Serialize/DeSerialize entities and use JSON.NET instead?

I have the following service contract for handling the City entity. For design reasons the City entity has IsReference=true, and therefore the default DataContractSerializer raise errors.

For the "GET" methods I can handle the situation with JsonConvert.DeserializeObject, but with "PUT,POST,DELETE" methods DataContractSerializer takes precedence and fails complaining for the IsReference entities cannot be serialized.

I have find this Post to implement IOperationBehavior and provide my own Serializer but I do not know how to integrate Json.NET with this. and I believe there should be more straight forward approach for this.

I’d appreciate any help or guidance regarding this scenario, or advice to other approaches.

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class CityService
{
    [Description("Get all Cities")]  
    [WebGet(UriTemplate = "")]
    public Message Cities()
    {

    }

    [Description("Allows the details of a single City to be updated.")]
    [WebInvoke(UriTemplate = "{code}", Method = "PUT")]
    public Message UpdateCity(string code, City city)
    {
    }
}

Many thanks

Hossam

+1  A: 

Is there some reason why you want to use the Json.NET library specifically. If you want to return JSON, why not just use the ResponseFormat property from the WebGet and WebInvoke attributes?

[WebGet(UriTemplate = "", ResponseFormat = WebMessageFormat.Json)]

That should for most cases. What version of WCF are you running? Any reason you're returning a Message type rather than the actual type?

Steve Michelotti
It's WCF4. In my web.config, my <standardEndpoint> has defaultOutgoingResponseFormat="Json", so I do not have to decorate the service methods. By design all of my Entities have [IsReference=true] and cannot get serialized with the default DataContractSerializer.So I have to use onther Serializer like Json.net that can handle Entities with [IsReference=true].I'm returning the Message type to not get my response serialzed twice, once by json.net and then by DataContractSerializer.If I returned the actuall type I'd get invalid json like "{\"City\":\"Cairo\"}"Thanx for your reply.
Hossam
So this works for you if you do not use the IsReference attribute but you have to use it by design for another reason?
Steve Michelotti
Correct, IsReference is the only issue. This is reported in many posts DataContractJsonSerializer can not serialize entities marked with IsReference=true. That's why I'm looking to use another Serializer.Many Thanks
Hossam
+3  A: 

The usage of Extending Encoders and Serializers (see http://msdn.microsoft.com/en-us/library/ms733092.aspx) or other methods of Extending WCF like usage of DataContractSerializerOperationBehavior is very interesting, but for your special problem there are easier solution ways.

If you already use Message type to return the results an use WCF4 you can do something like following:

public Message UpdateCity(string code, City city)
{
    MyResponseDataClass message = CreateMyResponse();
    // use JSON.NET to serialize the response data
    string myResponseBody = JsonConvert.Serialize(message);
    return WebOperationContext.Current.CreateTextResponse (myResponseBody,
                "application/json; charset=utf-8",
                Encoding.UTF8);
}

In case of errors (like HttpStatusCode.Unauthorized or HttpStatusCode.Conflict) or in other situations when you need to set a HTTP status code (like HttpStatusCode.Created) you can continue to use WebOperationContext.Current.OutgoingResponse.StatusCode.

As an alternative you can also return a Stream (see http://blogs.msdn.com/b/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx and http://msdn.microsoft.com/en-us/library/ms732038.aspx) instead of Message to return any data without additional default processing by Microsoft JSON serializer. In case of WFC4 you can use CreateStreamResponse (see http://msdn.microsoft.com/en-us/library/dd782273.aspx) instead of CreateTextResponse. Don't forget to set stream position to 0 after writing in the stream if you will use this technique to produce the response.

Oleg
Oleg, many thanks, it works like a charm by returning Stream type, it stops Microsft serializer.I am aware of DataContractSerializerOperationBehavior, but it takes me to inheret my own Serializer from XmlObjectSerializer which is not an easy task.Your proposal is much simpler and straight forward, Thank you once more.
Hossam
How does that handle deserializing the incoming City object?
Christopher Stott
@Christopher Stott: See for example http://msdn.microsoft.com/en-us/library/ms734675.aspx starting with "Reading Messages".
Oleg
@Oleg - From that link, it looks like UpdateCity would have to take a Message parameter to be able to deserialize with JSON.NET. Is that correct? Any way around it?
Christopher Stott