【问题标题】:WCF - Control namespaces when deserializingWCF - 反序列化时控制命名空间
【发布时间】: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)。

我想让我们的网络服务接受这些消息。有没有办法做到这一点 - 最好使用属性?

【问题讨论】:

    标签: c# xml wcf serialization


    【解决方案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 命名空间中。但是,您可以结合使用MessageContractMessageBodyMember 属性来执行此操作。另一个可能更简单的替代方法是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
    }
    

    【讨论】:

      猜你喜欢
      • 2012-09-01
      • 2015-10-05
      • 2011-03-09
      • 2015-11-03
      • 1970-01-01
      • 2012-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多