WCF - 反序列化时控制命名空间
Posted
技术标签:
【中文标题】WCF - 反序列化时控制命名空间【英文标题】:WCF - Control namespaces when deserializing 【发布时间】:2011-10-30 14:11:19 【问题描述】:一个外部 (java) 应用程序向我们的 Web 服务发送消息。此消息包含多个命名空间:
<StUF:Fo01Bericht xmlns:StUF="http://www.egem.nl/StUF/StUF0300">
<LVO:stuurgegevens xmlns:LVO="http://www.vrom.nl/StUF/sector/lvo/0305">
<StUF:versieStUF>0300</StUF:versieStUF>
<StUF:berichtcode>Fo01</StUF:berichtcode>
</LVO:stuurgegevens>
<StUF:body>
<StUF:code>200</StUF:code>
<StUF:plek>LVO</StUF:plek>
<StUF:omschrijving>test</StUF:omschrijving>
</StUF:body>
</StUF:Fo01Bericht>
WCF 服务无法反序列化此消息,因为第二行的 LVO 前缀(根据 WSDL 应该是 StUF)。
我想让我们的网络服务接受这些消息。有没有办法做到这一点 - 最好使用属性?
【问题讨论】:
【参考方案1】:我在接受来自第三方的肥皂消息时遇到了这个问题。
这是我正在发送的 soapHeader(注意 UsernameToken 中的不同命名空间):
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wssu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>userName</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">password</wsse:Password>
<wsse:Nonce>nonce</wsse:Nonce>
<wssu:Created>2015-02-19T16:24:32Z</wssu:Created>
</wsse:UsernameToken>
</wsse:Security>
为了正确反序列化,我需要在我的 DataContract 中实现 IxmlSerializable,如下所示:
[DataContract(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", Name = "Security")]
public partial class SecurityHeaderType
[XmlElementAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
[DataMember]
public UsernameToken UsernameToken get; set;
public class UsernameToken : IXmlSerializable
public string Username get; set;
public string Password get; set;
public string Nonce get; set;
public string Created get; set;
public XmlSchema GetSchema()
throw new NotImplementedException();
public void ReadXml(XmlReader reader)
Dictionary<string, string> secDictionary;
string xml = reader.ReadOuterXml();
using (var s = GenerateStreamFromString(xml))
secDictionary =
XElement.Load(s).Elements()
.ToDictionary(e => e.Name.LocalName, e => e.Value);
Username = secDictionary["Username"];
Password = secDictionary["Password"];
Nonce = secDictionary["Nonce"];
Created = secDictionary["Created"];
然后我能够反序列化我的标题,如下所示:
if (OperationContext.Current.IncomingMessageHeaders.FindHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd") != -1)
var securityHeader = OperationContext.Current.IncomingMessageHeaders.GetHeader<SecurityHeaderType>("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
【讨论】:
看来你自己找到了答案。因为,我换了另一个雇主,我再也无法访问代码了,但这与我所做的基本相同。【参考方案2】:我不相信您可以通过修改 DataContract 命名空间来实现这一点。原因是 DataMember 属性合理地假设类属性与类本身位于相同的 XML 命名空间中。但是,您可以结合使用MessageContract 和MessageBodyMember 属性来执行此操作。另一个可能更简单的替代方法是implement a message inspector 重新格式化soap 消息以符合预期的XML 模式。
【讨论】:
我们不使用默认的 WCF 序列化。该服务依赖于 XML 序列化。我已经尝试使用 XmlNamespaceDeclarations 属性。但这似乎不起作用。 通过实现 IXmlSerializable 接口解决了这个问题。 @WvanNoort 你能详细说明你做了什么吗?我现在也有同样的问题。【参考方案3】:我和你和德克兰有同样的问题。 Declan 的答案很有效,但我发现它对我来说并不那么干净。所以对我来说最好的解决方案是创建soap安全头模型:
[XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public partial class Security
[XmlElement]
public UsernameToken UsernameToken get; set;
[XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class UsernameToken
[XmlAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
public string Id get; set;
[XmlElement]
public string Username get; set;
[XmlElement]
public Password Password get; set;
[XmlElement]
public Nonce Nonce get; set;
public class Password
[XmlAttribute]
public string Type get; set;
[XmlText]
public string Value get; set;
public class Nonce
[XmlAttribute]
public string EncodingType get; set;
[XmlText]
public string Value get; set;
然后我试图将这个 SOAP 反序列化为前面的模型:
var soapSecurityHeaderIndex = OperationContext.Current.IncomingMessageHeaders.FindHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
if(soapSecurityHeaderIndex != -1)
var xmlReader = OperationContext.Current.IncomingMessageHeaders.GetReaderAtHeader(soapSecurityHeaderIndex);
var serializer = new XmlSerializer(typeof(Security));
var result = (Security)serializer.Deserialize(xmlReader);
// do something with result
【讨论】:
以上是关于WCF - 反序列化时控制命名空间的主要内容,如果未能解决你的问题,请参考以下文章