Friday, April 06, 2012 12:07 PMI would like to create a WCF REST Service that would return both Json and XML based on the "Accept" header in the request. I would like to use the XML serializer because I have more control over the xml output. For returning json I need to use the data contract serializer. Is it possible to configure both or implement a behavior in the channel that will use both serializers?
Friday, April 06, 2012 12:43 PM
Yes, this is possible, the only cavet is that you must return a message object. Use select/switch statement to choose your format then build your message and return it using the following:
This for Json:
WebOperationContext.Current.CreateJsonResponse()This for XML:
- Edited by Dragan Radovac Friday, April 06, 2012 12:43 PM
Friday, April 06, 2012 1:35 PM
The "WebOperationContext.Current.CreateXmlResponse()" uses the DataContract Serializer. I tested by having my OperationContract return a message object. I have an attribute in my Domain Object. When I viewed the results returned by the REST service the attribute was missing.
I also tested to make sure I have the domain object setup correctly. I did this by using the XML Serializer to serialize the object. The xml attribute did show up.
Any other ideas on how to setup a REST service that will use the XML Serializer for application/xml and the Data contract serializer for application/json?
Friday, April 06, 2012 2:31 PM
Hi, if you xml attribute is not showing up and by that you mean <?xml version="1.0" encoding="utf-8"?> then you can force it using CreatTextResponse like so:
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml" return WebOperationContext.Current.CreateTextResponse("<?xml version="1.0" encoding="utf-8"?><Field>field data<Field>")
You may have to screw around with getting your quotes into the string. Also, <Field>field data<Field> in this instance is where you would convert your serialized xml to string
- Proposed As Answer by Dragan Radovac Friday, April 06, 2012 6:36 PM
Friday, April 06, 2012 4:56 PM
That worked. Instead of updateing all of my operation contract would it be possible to do this in a custom formatter that implements IDispatchMessageFormatter? Or maybe some where else in the WCF channel like an custom IOperationInvoker?
Thanks again for the help.
Friday, April 06, 2012 6:09 PM
Yes, you could do that inside the message inspector. This is what you would do in BeforeSendReply:
Public Sub BeforeSendReply(ByRef reply As System.ServiceModel.Channels.Message, correlationState As Object) Implements System.ServiceModel.Dispatcher.IDispatchMessageInspector.BeforeSendReply Dim ms As MemoryStream = New MemoryStream Dim writer As XmlDictionaryWriter = XmlDictionaryWriter.CreateTextWriter(ms) reply.WriteMessage(writer) writer.Flush() Dim messageBody As String = Encoding.UTF8.GetString(ms.ToArray()) WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml" reply = WebOperationContext.Current.CreateTextResponse(messageBody) End Sub
Friday, April 06, 2012 7:50 PM
I tired that the message inspector but at that point in the channel the object that was returned by the service has already been serialized by the DataContractSerializer. So, it looks like the only solution is to have my operation contract return a Message. Below is the code I added to my service.
Thanks for the help!string accept = WebOperationContext.Current.IncomingRequest.Accept;
Message msg = null;
msg = WebOperationContext.Current.CreateJsonResponse<Grade>(result);
string xml = SerializeAsString(result);
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
msg = WebOperationContext.Current.CreateTextResponse(xml, "application/xml", Encoding.Default);