Eakan Gopalakrishnan
Eakan Gopalakrishnan

Reputation: 890

WCF service returns XML response when requesting json despite setting accept: application/json

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:

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.

Upvotes: 1

Views: 2690

Answers (2)

thudbutt
thudbutt

Reputation: 1521

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.

Upvotes: 1

Petar Vučetin
Petar Vučetin

Reputation: 3615

I think you need to add

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

To <system.serviceModel> <behaviors> section

Upvotes: 1

Related Questions