WCF 服务中返回任意字符串的技巧

在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默认的序列化机制,直接返回原始的字符串数据。这对于需要返回特定格式数据,或者需要绕过序列化限制的场景非常有用。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485