Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF - Control namespaces when deserializing

An external (java) app sends messages to our web service. This message contains multiple namespaces:

<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>

The WCF service cannot deserialize this message because of the LVO prefix on the second line (it should have been StUF according to the WSDL).

I want to get our web service to accept these messages. Is there a way to do this - preferably using attributes?

like image 323
W van Noort Avatar asked Oct 10 '22 05:10

W van Noort


2 Answers

I had this issue when accepting soap message from a third party.

Here is the soapHeader i was being sent(Note the different namespaces within 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>

To deserialize properly i needed to implement IxmlSerializable, in my DataContract, as below:

[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"];          

    }

I was then able to deserialize my header as below:

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");
}
like image 118
Declan Avatar answered Oct 19 '22 08:10

Declan


I don't believe you can accomplish that through modifying the DataContract namespaces. The reason is the DataMember attribute reasonably assumes the class properties are in the same XML namespace as the class itself. However, you may be able to do this with a combination of MessageContract and MessageBodyMember attributes. Another possibly simpler alternative is to implement a message inspector to reformat the soap message to comply with the expected XML schema.

like image 43
Sixto Saez Avatar answered Oct 19 '22 06:10

Sixto Saez