Extraction of Body from Envelope causing namespace issue

Hi

I'm pretty new to BizTalk and having an issue around how BizTalk handles envelopes.  Using fiddler I can see the message below is being returned from a third party SOAP API (SalesForce) to my BizTalk 2010 server:

HTTP/1.1 200 OK
Date: Tue, 20 Jan 2015 11:05:03 GMT
Set-Cookie: BrowserId=oPAPqlH7TbmO64uWvuSduw;Path=/;Domain=.salesforce.com;Expires=Sat, 21-Mar-2015 11:05:03 GMT
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: text/xml;charset=UTF-8
Content-Length: 706

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns="urn:enterprise.soap.sforce.com"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
 <soapenv:Header>
  <LimitInfoHeader>
   <limitInfo>
    <current>54</current>
    <limit>5000000</limit>
    <type>API REQUESTS</type>
   </limitInfo>
  </LimitInfoHeader>
 </soapenv:Header>
 <soapenv:Body>
  <queryResponse>
   <result>
    <done>true</done>
    <queryLocator xsi:nil="true"/>
     <records xsi:type="sf:Contact">
     <sf:Id xsi:nil="true"/>
     <sf:FirstName>Colin</sf:FirstName>
     <sf:LastName>Smith</sf:LastName>
    </records>
    <size>1</size>
   </result>
  </queryResponse>
 </soapenv:Body>
</soapenv:Envelope>

I'm use a Dynamic Solicit-Response Send Port in this communication as I have to set the URL from within the orchestration.  You can see the envelope includes several namespaces, including xmlns:sf="urn:sobject.enterprise.soap.sforce.com".  When BizTalk receives this envelope I'm guessing it does its best to extract the Body section for use in my orchestration as I can see when it errors, the message it has is:

<queryResponse xmlns="urn:enterprise.soap.sforce.com">
 <result>
  <done>true</done> 
  <queryLocator xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /> 
  <records xsi:type="sf:Contact" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <sf:Id xsi:nil="true" xmlns:sf="urn:sobject.enterprise.soap.sforce.com" /> 
   <sf:FirstName xmlns:sf="urn:sobject.enterprise.soap.sforce.com">Colin</sf:FirstName> 
   <sf:LastName xmlns:sf="urn:sobject.enterprise.soap.sforce.com">Smith</sf:LastName> 
  </records>
  <size>1</size> 
 </result>
</queryResponse>

So for elements sf:Id, sf:FirstName and sf:LastName, BizTalk has kindly added the 'sf' namespace.  Unfortunately, for the 'records' element which specifies the type sf:Contact BizTalk has not added the 'sf' namespace, so I get the error below when I try to use the message within my orchestration:

Error details: Unable to read the stream produced by the pipeline.
Details: The value 'sf:Contact' is invalid according to its schema type 'http://www.w3.org/2001/XMLSchema:QName' - 'sf' is an undeclared prefix. 

Any help on how I can work around this issue would be very greatly appreciated.

Colin.


  • Edited by ColinCG Tuesday, January 20, 2015 12:28 PM Improved formatting
January 20th, 2015 2:39pm

Which pipeline are you using?
Free Windows Admin Tool Kit Click here and download it now
January 20th, 2015 2:54pm

I'm using the XMLReceive pipeline on the Dynamic Solicit-Response Send Port.  In my orchestration, the next step is I try to output the message to a file using XMLTransmit and that's the point where I seem receive the error.
January 20th, 2015 2:59pm

There are two options here :

1)your salesforce  API should do a modification from there side to send you proper  response without sf prefix added .

2) Cream a custom send pipeline component to parse your incoming message and format it as per normal xml .

Thanks

Abhishek

Free Windows Admin Tool Kit Click here and download it now
January 20th, 2015 3:24pm

Hi,

Try the output as pass through and see what exactly you are receiving. Then based on your requirements you can decide which route to take. This is the response from SF so you will have to raise with them to give you a well formed XML response.

January 20th, 2015 3:39pm

You asked this question before no?

Anyway, I see the problem now.  It seems SF is using a valid xml format that, most probably WCF or maybe the bridge Adapter, is not expecting. 

I'd bet you are using the Body option of the "Inbound BizTalk message body" section of the Messages tab and it's not descending the namespaces properly.

Instead of using the Body option, create a BizTalk Envelope Schema that represents the SOAP message with the Body option set to soapenv:Body.

The XmlDisassembler will then Debatch out the queryResponse message and it's 100% for sure it will descent the namespace properly.

  • Marked as answer by ColinCG Friday, January 23, 2015 12:03 PM
Free Windows Admin Tool Kit Click here and download it now
January 20th, 2015 4:33pm

Thanks for the replies guys.

DPS Bali - I tried the Pass Through pipeline on the port I am using to save the recieved message to a file.  It comes out as the xml in the original post (the one without the envelope).  So it saves the file without error, but the XML within the file is then not well formed as its still missing the 'sf' namespace.

Johns-305 - Yes sorry, this is quite similar to my last post, the difference being that I realised through using fiddler that there was an envelope and that had the 'sf' namespace so thought I should start an new thread.  I agree with you that SF response does seem valid and if I write a basic c# app to consume it there are no problems.

I would really like to try your suggestion, but I'm using a dynamic port so don't have the Configure button or Messages tab on the send port.  Would I need a statement like this when setting up the port - queryRequestMessage(WCF.InboundBodyLocation) = "UseEnvelope";?  I'm still pretty much a beginner on BizTalk I'm not sure where the envelope schema would come into this, could you go into a little more detail please or are there any examples you know of?


January 20th, 2015 5:27pm

Yes, WCF.InboundBodyLocation = "UseEnvelope" will return the entire SOAP message.  So you would set that on the Request message for your Dynamic Port with all the other properties.

At that point, its just basic Xml Debatching, the fact that it's a SOAP Envelope isn't relevant.

Here's one of many posts on Xml Debatching in BizTalk: http://www.codeproject.com/Articles/507336/Envelope-Schema-and-Debatching

The procedure is essentially identical regardless of the source, file, SQL, SOAP, etc.

Free Windows Admin Tool Kit Click here and download it now
January 20th, 2015 7:39pm

This is the envelope schema I've come up with but I don't think its right:

  <?xml version="1.0" encoding="utf-16" ?> 
  <xs:schema xmlns="http://SalesForce.Integration.Login.Schemas.QueryResponseEnvelope" 
     xmlns:b="http://schemas.microsoft.com/BizTalk/2003" 
     targetNamespace="http://SalesForce.Integration.Login.Schemas.QueryResponseEnvelope" 
     xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:annotation>
      <xs:appinfo>
        <b:schemaInfo is_envelope="yes" /> 
      </xs:appinfo>
    </xs:annotation>
    <xs:element name="soapenv">
      <xs:annotation>
        <xs:appinfo>
          <b:recordInfo body_xpath="/*[local-name()='soapenv' and 
             namespace-uri()='http://SalesForce.Integration.Login.Schemas.QueryResponseEnvelope']/*[local-name()='queryResponses' and 
             namespace-uri()='']" /> 
        </xs:appinfo>
      </xs:annotation>
      <xs:complexType>
        <xs:sequence>
          <xs:element name="queryResponses">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="queryResponse">
                  <xs:complexType>
                    <xs:sequence>
                      <xs:any /> 
                    </xs:sequence>
                  </xs:complexType>
                </xs:element>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
    </xs:element>
  </xs:schema>

Also, do I need to create a custom pipeline with an XML Disassembler using this envelope schema?

Really appreciate your help on this, I'm pretty confused at the moment.

January 20th, 2015 8:59pm

To simplify things, the XmlDisassembler is not too picky about the Envelope, so long as the Body (Body XPath property) and all its direct ancestors are there, the rest is ignored.

So, your Envelope Schema really needs only the Envelope and Body Elements.  The Target Namespace of Envelope is still http://schemas.xmlsoap.org/soap/envelope/

No, it won't validate but that doesn't matter.  The queryResponse definition does not need to be there either, Body can be last element.

I usually recommend using a custom Pipeline with at least the Envelope Schemas set and you should probably set the Document Schemas property too for good measure.

Free Windows Admin Tool Kit Click here and download it now
January 20th, 2015 11:20pm

I think I'm getting closer.  Here's what I have so far. I'm setting WCF.InboundBodyLocation = "UseEnvelope" on the request message.  I've created a new receive pipeline call 'ReceiveAndDebatch' and I'm using that on the Send port. The pipeline has an XML Disassembler component with the Envelope Schema set to a new schema called queryResponseEnvelope.  The queryResponseEnvelope schema looks like this:

  <?xml version="1.0" encoding="utf-16" ?> 
  <xs:schema xmlns="http://schemas.xmlsoap.org/soap/envelope/" 
      xmlns:b="http://schemas.microsoft.com/BizTalk/2003" 
      targetNamespace="http://schemas.xmlsoap.org/soap/envelope/" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:annotation>
      <xs:appinfo>
        <b:schemaInfo is_envelope="yes" 
            xmlns:b="http://schemas.microsoft.com/BizTalk/2003" /> 
      </xs:appinfo>
    </xs:annotation>
    <xs:element name="soapenv">
      <xs:annotation>
        <xs:appinfo>
          <b:recordInfo body_xpath="/*[local-name()='soapenv' and 
              namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/']/
              *[local-name()='Body' and namespace-uri()='']" /> 
        </xs:appinfo>
      </xs:annotation>
      <xs:complexType>
        <xs:sequence>
          <xs:element name="Body">
            <xs:complexType>
              <xs:sequence>
                <xs:any /> 
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:complexType>
    </xs:element>
  </xs:schema>

However, the error I'm now getting when receiving the response message is:

There was a failure executing the response(receive) pipeline: "SalesForce.Integration.Login.Orchestrations.ReceiveAndDebatch, SalesForce.Integration.Login.Orchestrations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c9efa037fafdab29" Source: "XML disassembler" Send Port: "SalesForce.Integration.Login.Orchestrations_1.0.0.0_SalesForce.Integration.Login.Orchestrations.SFProcess_SF_SndRec_c9efa037fafdab29" URI: "https://cs18.salesforce.com/services/Soap/c/32.0/00D1100000074Fh/0DF1100000000c5" Reason: Document type "http://schemas.xmlsoap.org/soap/envelope/#Envelope" does not match any of the given schemas. 

Can you offer any further guidance on this?  Many thanks for your help.


January 21st, 2015 4:46pm

Is your new Envelope schema Deployed and configured in the Envelope section of the XmlDisassembler Component?

You should see this in Schemas list in BT Admin.

Free Windows Admin Tool Kit Click here and download it now
January 21st, 2015 5:41pm

Yes I've added the new envelope schema to the XMLDisassembler components Envelope Schemas collection.

I can also see the new envelope schema in the Schemas list of the application in BizTalk.

January 21st, 2015 6:16pm

Try deploying the Schema and Pipeline in different Projects (assemblies).
Free Windows Admin Tool Kit Click here and download it now
January 21st, 2015 10:39pm

The schema's are in their own project and the orchestration and pipeline in another project.  I've just tried moving the pipeline to the schemas project and also to its own new project, but unfortunately the sane error remains.  I've done some playing with my envelope schema but not made much progress.  Though if I change <xs:element name="soapenv"> to <xs:element name="Envelope" I get this error instead:

This Disassembler cannot retrieve body nodes using this XPath: "/*[local-name()='Envelope' and namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/']/*[local-name()='Body' and namespace-uri()='']".

/*[local-name()='Envelope' and namespace-uri()='http://schemas.xmlsoap.org/soap/envelope/']/*[local-name()='Body' and namespace-uri()='']  

January 22nd, 2015 4:16pm

Did you update the Body path using the Schema Editor?

As a reminder, at this point, it has nothing to do with SOAP, this is just basic Xml Detaching.

Generate an Instance of the Envelop Schema and see if it matches.

Free Windows Admin Tool Kit Click here and download it now
January 22nd, 2015 5:23pm

Although I can get the simple debatching online examples to work fine, I'm missing something on this one.  I'm sure what you're saying would fix my issue and someone with more experience than me would probably have no problems implementing your suggestion, so I've marked it as the answer.  I'll carry on playing with this in my spare time, as I find it quite interesting, but unfortunately time restraints on this project mean I have to move on now.  For the moment, my workaround is I take the xml returned from SalesForce, pass it to a simple c# helper class, insert the missing namespace and return it to BizTalk.  Not a bullet proof fix, but the message now validates and I can move forward.

A big thankyou for all your help on this, really appreciate all of your advice.

January 23rd, 2015 3:14pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics