I was searching all over the Internet, and yet I could not find any information about this seemingly simple task. Suppose you have an arbitrary string that you would like to return from a WCF (Windows Communication Foundation) service.
You can do one of the following on the service contract:
- Create a method/operation with a string return type
- Create a method/operation with a Stream return type in order to have full control over how serialization is performed. You can find a good explanation @ http://blogs.msdn.com/carlosfigueira/archive/2008/04/17/wcf-raw-programming-model-web.aspx
However, you may find yourself in a situation where you cannot return a Stream type because you are sending the response somewhere deep inside the WCF stack and you only have the
System.ServiceModel.Message type to work with. Here is the documentation of the Message class I am talking about - http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.message.aspx
Aside: If you have ever worked with RIA (Rich Internet Applications) such as Flash or Silverlight you will most likely be familiar with cross-domain policy files, such as crossdomain.xml (Flash) or clientaccesspolicy.xml (Silverlight). I am not going to go into why they are needed, but needless to say, I had to return one of these files depending on the request made from the client. Both of these files contain perfectly valid XML.
If you look carefully at the
Message.CreateMessage method you will see it has many overloads. At first, I tried this:
Message reply = Message.CreateMessage(MessageVersion.None, "", XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes("[XML goes here]"))));
This works fine as long as the XML you are passing to XmlReader does not contain DTD definitions. For some security reason having a DTD in the XML causes an exception on the
XmlReader.Create call. I was able to avoid an exception by setting the
ProhibitDtd property on
XmlReaderSettings to false, but WCF decided I was performing evil deeds, and independently decided to emit my XML without the DTD definition.
If you look at the overloads of
Message.CreateMessage you will quickly realize that you must serialize as XML. In my case, the DTD in the crossdomain.xml caused the headache, but what if you want to pass an arbitrary string such as "Hello World" back from the service as-is, what do you do then? Anything you may try will cause the default
DataContractSerializer to kick in and serialize your object. The catch is, you do not actually want serialization.
Here is the code that you need in order to return arbitrary text using WCF's Message class.
public class TextBodyWriter : BodyWriter
public TextBodyWriter(string message)
this.messageBytes = Encoding.UTF8.GetBytes(message);
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
writer.WriteBase64(this.messageBytes, 0, this.messageBytes.Length);
string response = "Hello World!";
Message reply = Message.CreateMessage(MessageVersion.None, null,
reply.Properties[WebBodyFormatMessageProperty.Name] = new WebBodyFormatMessageProperty(
WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";