如何让WCF序列化器不对SOAP Body内容编码,保留CDATA格式?
解决WCF序列化器不对SOAP Body中CDATA内容编码的问题
你不需要退回字符串模板方式,WCF提供了自定义序列化的能力,可以精准控制CDATA内容的输出,避免特殊字符被编码。以下是两种可行的解决方案:
方案1:扩展生成的WORKRequest类实现IXmlSerializable
利用生成类的partial特性,添加自定义序列化逻辑,手动将data字段包裹为CDATA节点,绕开默认的编码行为。
实现代码
在同一个命名空间下新建一个代码文件,扩展WORKRequest类:
using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; public partial class WORKRequest : IXmlSerializable { XmlSchema IXmlSerializable.GetSchema() => null; void IXmlSerializable.ReadXml(XmlReader reader) { // 客户端若无需反序列化请求,可简化实现 reader.ReadStartElement("WORK"); if (reader.Name == "data") { reader.ReadStartElement(); data = reader.NodeType == XmlNodeType.CDATA ? reader.Value : reader.ReadContentAsString(); reader.Read(); reader.ReadEndElement(); } reader.ReadEndElement(); } void IXmlSerializable.WriteXml(XmlWriter writer) { // 手动写入data节点并包裹CDATA,避免特殊字符编码 writer.WriteStartElement("data"); writer.WriteCData(data); writer.WriteEndElement(); } }
使用方式
保持原有调用逻辑不变,直接传入包含XML的字符串即可:
var request = new WORKRequest("<root><item>123</item></root>"); var response = client.WORK(request);
此时SOAP Body中的data节点会被序列化为:
<data><![CDATA[<root><item>123</item></root>]]></data>
方案2:手动构造SOAP消息(完全绕过自动序列化)
如果自定义序列化仍有兼容性问题,可以直接构造完整的SOAP信封,完全控制请求内容。
实现代码
using (var factory = new ChannelFactory<ANDR_servicePort>("ANDR_servicePort")) { var channel = factory.CreateChannel(); var cdataContent = "<root><item>123</item></root>"; // 手动构造符合要求的SOAP信封 var soapEnvelope = $@"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/""> <s:Body> <WORK xmlns=""http://soapEndpoint""> <data><![CDATA[{cdataContent}]]></data> </WORK> </s:Body> </s:Envelope>"; using (var stringReader = new StringReader(soapEnvelope)) using (var xmlReader = XmlReader.Create(stringReader)) { var message = Message.CreateMessage(xmlReader, int.MaxValue, MessageVersion.Soap11); var reply = ((IRequestChannel)channel).Request(message); // 反序列化回复得到WORKResponse var serializer = new XmlSerializer(typeof(WORKResponse)); using (var replyReader = reply.GetReaderAtBodyContents()) { var response = (WORKResponse)serializer.Deserialize(replyReader); // 处理返回结果 } } }
为什么你之前的尝试没成功?
- IClientMessageInspector时机不对:
BeforeSendRequest触发时消息尚未完成序列化,看不到编码后的字符;而WCF消息默认只读,无法在序列化后直接修改内容。 - XElement类型不兼容:你的契约使用
Rpc/Encoded风格,XmlSerializer无法直接将XElement序列化为Encoded格式的SOAP节点,因此抛出异常。
内容的提问来源于stack exchange,提问作者AlinF
相关产品推荐
相关产品推荐

