Friday, July 7, 2017

Retrieve data from web service with ws addressing

Leave a Comment

I have a web service on a client site from which I need to report.

Locally, I mimicked the service using the provided wsdls and have been able to report on these. However, now pointing at the client site I am unable to access the data as the service requires ws addressing headers to be included.

The webservice is expecting the below:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:add="http://www.w3.org/2005/08/addressing" xmlns:ns="CustomerNamespace" xmlns:sch="Schema.xsd">    <soapenv:Header>       <add:From>          <add:Address>Something</add:Address>          <add:ReferenceParameters>             <ns:TransactionGroupID>SomeOtherThing</ns:TransactionGroupID>             <ns:SenderID>911</ns:SenderID>          </add:ReferenceParameters>       </add:From>       <add:Action>Request</add:Action>       <add:MessageID>TestGUID</add:MessageID>    </soapenv:Header>    <soapenv:Body>       <sch:Request>          <sch:SearchCustomerSystem>SystemXYZ</sch:SearchCustomerSystem>           <sch:ServiceID>999999999999</sch:ServiceID>       </sch:Request>    </soapenv:Body> </soapenv:Envelope> 

At present, I ccan get SSRS to produce the below:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <Request xmlns="Schema.xsd">       <ServiceID>           999999999999         </ServiceID>     </Request>   </soap:Body> </soap:Envelope> 

Other than creating a custom data extension (which I would rather avoid), is there a way of getting the ws addressing headers into the request?

2 Answers

Answers 1

The following snippet is the part of our WSDL that may be helpful if you have ability to change your WSDL. You will likely only need a bit of the namespaces, particularly the "addressing" related items. The "wsaw" namespace is the one used on our Action attributes that live on wsdl:input attributes under path of wsdl:portType -> wsdl:operation.

  <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="OurTargetNamespaceHere" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" name="OurServiceNameHere" targetNamespace="OurTargetNamespaceHere">   <wsp:Policy wsu:Id="OurCustomPolicy_policy">     <wsp:ExactlyOne>       <wsp:All>         <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">           <wsp:Policy>             <sp:TransportToken>               <wsp:Policy>                 <sp:HttpsToken RequireClientCertificate="false"/>               </wsp:Policy>             </sp:TransportToken>             <sp:AlgorithmSuite>               <wsp:Policy>                 <sp:Basic256/>               </wsp:Policy>             </sp:AlgorithmSuite>             <sp:Layout>               <wsp:Policy>                 <sp:Strict/>               </wsp:Policy>             </sp:Layout>           </wsp:Policy>         </sp:TransportBinding>       </wsp:All>     </wsp:ExactlyOne>   </wsp:Policy> 

Answers 2

For this example I will be using C#

Using the expected envelope in your example the following classes were derived.

/// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://schemas.xmlsoap.org/soap/envelope/", IsNullable = false)] public partial class Envelope {     /// <remarks/>     public EnvelopeHeader Header { get; set; }     /// <remarks/>     public EnvelopeBody Body { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public partial class EnvelopeHeader {     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]     public From From { get; set; }     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]     public string Action { get; set; }     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "http://www.w3.org/2005/08/addressing")]     public string MessageID { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/08/addressing")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.w3.org/2005/08/addressing", IsNullable = false)] public partial class From {     /// <remarks/>     public string Address { get; set; }     /// <remarks/>     public FromReferenceParameters ReferenceParameters { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.w3.org/2005/08/addressing")] public partial class FromReferenceParameters {     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "CustomerNamespace")]     public string TransactionGroupID { get; set; }     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "CustomerNamespace")]     public ushort SenderID { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] public partial class EnvelopeBody {     /// <remarks/>     [System.Xml.Serialization.XmlElementAttribute(Namespace = "Schema.xsd")]     public Request Request { get; set; } }  /// <remarks/> [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "Schema.xsd")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "Schema.xsd", IsNullable = false)] public partial class Request {     /// <remarks/>     public string SearchCustomerSystem { get; set; }     /// <remarks/>     public ulong ServiceID { get; set; } } 

Using the above classes, the following Unit Test will be used to demonstrate

a way of getting the ws addressing headers into the request

[TestClass] public class MyTestClass {     [TestMethod]     public void _ws_addressing_headers_into_the_request() {          var xmlWithBodyOnly = GetEnvelopFromSSRS();         var header = BuildHeader();         var result = AppendHeader(xmlWithBodyOnly, header);      }      private static EnvelopeHeader BuildHeader() {         var header = new EnvelopeHeader {             From = new From {                 Address = "Someting",                 ReferenceParameters = new FromReferenceParameters {                     SenderID = 911,                     TransactionGroupID = "SomeOtherThing"                 }             },             Action = "Request",             MessageID = "SomeGuid"         };         return header;     }      private static string GetEnvelopFromSSRS() {         var xmlWithBodyOnly = @" <soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>   <soap:Body>     <Request xmlns='Schema.xsd'>       <ServiceID>           999999999999         </ServiceID>     </Request>   </soap:Body> </soap:Envelope>";         return xmlWithBodyOnly;     }      private string AppendHeader(string xml, EnvelopeHeader header) {         var result = string.Empty;         // convert string to stream         var data = Encoding.UTF8.GetBytes(xml);         using (var inStream = new MemoryStream(data)) {             // Create an instance of the XmlSerializer specifying type and namespace.             var serializer = new XmlSerializer(typeof(Envelope));             //Deseiralize XML to something we can work with             var envelope = (Envelope)serializer.Deserialize(inStream);             if (envelope != null) {                 //Append the header                 envelope.Header = header;                 //Serialize the envelope back to XML                 using (var outStream = new MemoryStream()) {                     serializer.Serialize(outStream, envelope);                     result = Encoding.UTF8.GetString(outStream.ToArray());                 }             }         }         return result;     } } 

Explanation.

 var xmlWithBodyOnly = GetEnvelopFromSSRS(); 

mimics getting what you have been able to produce via SSRS based on the example provided in your original question.

 var header = BuildHeader(); 

Using the derived classes you can easily create and populate the necessary properties for your header as you see fit

private static EnvelopeHeader BuildHeader() {     var header = new EnvelopeHeader {         From = new From {             Address = "Someting",             ReferenceParameters = new FromReferenceParameters {                 SenderID = 911,                 TransactionGroupID = "SomeOtherThing"             }         },         Action = "Request",         MessageID = "SomeGuid"     };     return header; } 

Now for the meat of the matter.

var result = AppendHeader(xmlWithBodyOnly, header); 

Once you have the envelope and the header you are now ready to append the ws addressing header to the request

private string AppendHeader(string xml, EnvelopeHeader header) {     var result = string.Empty;     // convert string to stream     var data = Encoding.UTF8.GetBytes(xml);     using (var inStream = new MemoryStream(data)) {         // Create an instance of the XmlSerializer specifying type and namespace.         var serializer = new XmlSerializer(typeof(Envelope));         //Deseiralize XML to something we can work with         var envelope = (Envelope)serializer.Deserialize(inStream);         if (envelope != null) {             //Append the header             envelope.Header = header;             //Serialize the envelope back to XML             using (var outStream = new MemoryStream()) {                 serializer.Serialize(outStream, envelope);                 result = Encoding.UTF8.GetString(outStream.ToArray());             }         }     }     return result; } 

The comments in the code explain what was done.

For the above example, given the following envelope

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <Request xmlns="Schema.xsd">       <ServiceID>           999999999999         </ServiceID>     </Request>   </soap:Body> </soap:Envelope> 

When used in the above code produces the following output.

<?xml version="1.0"?> <Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/soap/envelope/">   <Header>     <From xmlns="http://www.w3.org/2005/08/addressing">       <Address>Someting</Address>       <ReferenceParameters>         <TransactionGroupID xmlns="CustomerNamespace">SomeOtherThing</TransactionGroupID>         <SenderID xmlns="CustomerNamespace">911</SenderID>       </ReferenceParameters>     </From>     <Action xmlns="http://www.w3.org/2005/08/addressing">Request</Action>     <MessageID xmlns="http://www.w3.org/2005/08/addressing">SomeGuid</MessageID>   </Header>   <Body>     <Request xmlns="Schema.xsd">       <ServiceID>999999999999</ServiceID>     </Request>   </Body> </Envelope> 

This output can now be used to make your request to the web service as desired. The models can also be modified as needed based on what is required for the web service request.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment