在Windows Communication Foundation (WCF)服务中,经常需要返回字符串数据。通常情况下,这可以通过定义一个返回类型为string的方法来实现。然而,有时候可能需要更灵活的控制,比如返回一个Stream类型,以便完全控制序列化过程。但如果发现自己无法返回Stream类型,因为需要在WCF堆栈的深处发送响应,而只能使用System.ServiceModel.Message类型,那么就需要一些额外的技巧了。
如果曾经使用过RIA(Rich Internet Applications)如Flash或Silverlight,很可能熟悉跨域策略文件,比如crossdomain.xml(Flash)或clientaccesspolicy.xml(Silverlight)。虽然这里不会深入讨论为什么需要这些文件,但可以说,需要根据客户端的请求返回这些文件之一。这些文件都包含有效的XML。
在Message.CreateMessage方法中,可以看到它有很多重载。最初,尝试了以下代码:
Message reply = Message.CreateMessage(MessageVersion.None,
"",
XmlReader.Create(
new MemoryStream(Encoding.UTF8.GetBytes(
"[XML goes here]"
))
));
只要传递给XmlReader的XML不包含DTD定义,这种方法就可以正常工作。出于某些安全原因,XML中的DTD会导致XmlReader.Create调用抛出异常。通过设置XmlReaderSettings的ProhibitDtd属性为false,可以避免异常,但WCF决定正在执行不正当行为,并独立决定不包含DTD定义来发出XML。
如果仔细观察Message.CreateMessage的重载,很快就会意识到必须将其序列化为XML。在情况下,crossdomain.xml中的DTD造成了麻烦,但如果想从服务中返回一个任意的字符串,比如"Hello World",该怎么做呢?尝试的任何方法都会导致默认的DataContractSerializer介入并序列化对象。
关键是,实际上不想进行序列化。以下是使用WCF的Message类返回任意文本所需的代码。
/// <summary>
/// Necessary to write out the contents as text (used with the Raw return type)
/// </summary>
public class TextBodyWriter : BodyWriter
{
byte[] messageBytes;
public TextBodyWriter(string message)
: base(true)
{
this.messageBytes = Encoding.UTF8.GetBytes(message);
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("Binary");
writer.WriteBase64(this.messageBytes, 0, this.messageBytes.Length);
writer.WriteEndElement();
}
}
以下是返回原始文本给客户端的示例代码:
string response = "Hello World!";
Message reply = Message.CreateMessage(MessageVersion.None, null, new TextBodyWriter(response));
// very important - forces WCF to serialize the message body contents as "Raw" which effectively means no serialization
reply.Properties[WebBodyFormatMessageProperty.Name] = new WebBodyFormatMessageProperty(WebContentFormat.Raw);
// can also be "application/xml" or anything you prefer
WebOperationContext.Current.OutgoingResponse.ContentType = "text/plain";
通过这种方式,可以避免WCF默认的序列化机制,直接返回原始的字符串数据。这对于需要返回特定格式数据,或者需要绕过序列化限制的场景非常有用。