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 t开发者_如何学Pythonhis - preferably using attributes?
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");
}
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.
I have the same problem as you and Declan. The Declan answer was working but I find it not so clean for me. So for me the best solution was to create soap security header models:
[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; }
}
And then I was trying to deserialize this SOAP to those model ahead:
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
}
精彩评论