Reputation: 890
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:
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?AlreadyExisted
to true
, but that didn't help at all.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:
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
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
Upvotes: 1
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