1

I have a WCF service that returnsa simple DTO that looks almost like this:

    [DataContract]
[KnownType(typeof(TimeTriggerCreateResult))]
[KnownType(typeof(ScheduleCreateResult))]
public class TriggerCreateResult
{
    [DataMember(Order = 1)] public bool AlreadyExisted;
    [DataMember(Order = 2)] public int SchedulerId; // TODO: rename to ScheduleId
    [DataMember(Order = 3, EmitDefaultValue = false)] public int TriggerId;
    [DataMember(Order = 4)] public ScheduleType ScheduleType;

    public NewSchedule Schedule;
}
[DataContract]
public class TimeTriggerCreateResult : TriggerCreateResult
{
    public TimeTriggerCreateResult()
    {
        ScheduleType = ScheduleType.TimeTrigger;
    }

    public TimeTriggerDto TimeTrigger;
    [DataMember] public List<DateTuple> NextRun;
    public List<DateTuple> OlderRuns;
}
[Description("Create Schedule")]
        [OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "schedules/create")]
        TriggerCreateResult CreateNewSchedule(ScheduleDto scheduleDto);
[DataContract]
public enum ScheduleType
{
    [EnumMember] NoTrigger = 0,
    [EnumMember] TimeTrigger = 1,
}

This service does a lot of complicated stuff behind the scenes but returns the a little DTO with the corresponding properties mentioned in its definition.

I consume this service using the following key=>value in the header: accept:application/json but the irony is that I get an XML response when the service creates a new schedule. That is the first time a schedule is created, it returns an XML response. Wheras if the same schedule is attempted to be created again, then I get a JSON response, i.e. if the schedule already existed in the database. We do not manually serialize in different response formats. We solely rely on WCF's serialization/deserialization.

I have tried answers like REST WCF service returns XML response but not JSON response to trace the problem, but haven't got any useful information out of it. I have wasted two days entirely trying different combinations like:

  • Adding KnownTypes(typeof(ScheduleType)) to the TriggerCreateResult DTO just in case this was a serialization problem. But if it was a serialization problem, wouldn't it have thrown an exception?
  • Because it always returned a json when the schedule already existed in the database, I tried setting AlreadyExisted to true, but that didn't help at all.
  • I can mask the problem and always force a json response by using the RequestFormat = WebMessageFormat.Json,ResponseFormat = WebMessageFormat.Json in the WebInvoke of the operationcontract declaration. And also by making sure that all the enumeration types used in the DTO, ScheduleType is decorated with a DataContract attribute and has its members declared as EnumMember. But then again, even though the response is a JSON as expected the response header contains, Content-Type: application/xml.

But I want to know what is causing this automatic XML serialization when JSON format is requested even when no serialization exception is encountered. I know this because we tried logging and tracing as mentioned in one of the other questions. It just silently gives a response with HTTP 200 but return XML data instead of JSON data when what is expected is JSON.

What makes this weird is that, this service had always returned a JSON response whenever it was requested to return so, but a recent change introduced the enum property ScheduleType which is being initialized to a particular type inside the constructor of the corresponding DTO, example inside TimeTriggerCreateResult it is initialized ot TimeTrigger. Ever since, it has been behaving weird. The response of the service thereafter has been in an XML format, when it created a new schedule that never existed in the DB and when this happens, the bool AlreadyExisted would have the value of false. But if the same request was done again, then it returns a JSON response, but with AlreadyExisted, now being true.

A sample xml response:

enter image description here

I'm not an expert in all things WCF. SO I'd like to know what can cause the WCF serialization to silently return an XML when a JSON is requested for.

I have wasted considerable time (about 5-6 hours) trying to understand what is going on by testing various different settings. I wouldn't want to make a web.config change for this as this is the only service affected by this magical behaviour. But I have failed miserably to understand this rather unnatural phenomenon. Please help if you have any ideas.

2
  • What's the content of XML response? Commented Mar 23, 2016 at 21:56
  • the XML response is a valid deserialized response of the TimeTriggerCreateResult DTO in an XML format. Do you want a sample content? Commented Mar 24, 2016 at 2:34

2 Answers 2

1

I think you need to add

  <endpointBehaviors>
    <behavior name="endpointBehavior">
      <enableWebScript />
      <webHttp defaultBodyStyle="Wrapped" defaultOutgoingResponseFormat="Json" />
    </behavior>
  </endpointBehaviors>

To <system.serviceModel> <behaviors> section

Sign up to request clarification or add additional context in comments.

2 Comments

I really appreciate your suggestion. What I'm really trying to understand is why would WCF serialization return an XML when I request a JSON. I wouldn't want to change the default endpoint behaviour to JSON as other services in the project are fetched as XML.
It's a default shape of the message formatter. Using a behavior you are changing the shape of this channel message formatter.
1

If you want the format of the response to be based on the accept header of the request, then you need to set the AutomaticFormatSelectionEnabled property of the WebHttpEndpoint or WebHttpBehaviour.

<system.serviceModel>
  <behaviors> 
    <endpointBehaviors> 
      <behavior> 
        <webHttp automaticFormatSelectionEnabled="true" /> 
      </behavior> 
    </endpointBehaviors>
  </behaviors> 
  <standardEndpoints>  
    <webHttpEndpoint> 
      <!-- the "" standard endpoint is used by WebServiceHost for auto creating a web endpoint. --> 
      <standardEndpoint name="" helpEnabled="true" />
    </webHttpEndpoint>
  </standardEndpoints> 
</system.serviceModel>

See MSDN for further details. The best format to use is determined by checking the following in order

  1. The media types in the request message’s Accept header.
  2. The content-type of the request message.
  3. The default format setting in the operation.
  4. The default format setting in the WebHttpBehavior.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.