2

I'm working with a client to integrate their external vendors system into Salesforce.com. Unfortunately, the WSDL the vendor provides does not work with Salesforce.com. There appear to be three issues:

  1. Multiple endpoints. This is easily resolved by using the FuseIT Explorer WSDL2Apex utility.
  2. The response is defined as <s:any/> rather than a specific response structure. Apparently, Salesforce.com will not support a response that is not fully defined. Attempting to define the full response (replacing <s:any/>) causes an issue with duplicated defined element names.
  3. Both the request and the response have names defined as UpdateClearStarOrderInfo. This causes Salesforce to pick one of the defined UpdateClearStarOrderInfo element structures to use for both the request and the response. The calls fails because the expected structure is different. Renaming one of those causes the call to fail because of an undefined element either in the request or the response.

Does anyone know if there's a way to define a WSDL with two different elements that share the same name? And/or is there another way to approach fixing this to get it to work properly in Salesforce.com?

Original Request and Response from the WSDL:

<s:element name="UpdateClearStarOrderInfo">
  <s:complexType>
    <s:sequence>
      <s:element minOccurs="1" maxOccurs="1" name="BOID" type="s:int"/>
        <s:element minOccurs="0" maxOccurs="1" name="CustID" type="s:string"/>
        <s:element minOccurs="0" maxOccurs="1" name="UserName" type="s:string"/>
        <s:element minOccurs="0" maxOccurs="1" name="Password" type="s:string"/>
        <s:element minOccurs="0" maxOccurs="1" name="DonorID" type="s:string"/>
        <s:element minOccurs="0" maxOccurs="1" name="ProfileID" type="s:string"/>
        <s:element minOccurs="0" maxOccurs="1" name="OrderID" type="s:string"/>
      </s:sequence>
    </s:complexType>
</s:element>
<s:element name="UpdateClearStarOrderInfoResponse">
  <s:complexType>
    <s:sequence>
      <s:element minOccurs="0" maxOccurs="1" name="UpdateClearStarOrderInfoResult">
        <s:complexType mixed="true">
          <s:sequence>
            <s:any/>
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:sequence>
  </s:complexType>
</s:element>

Expected Call Payload:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org">
   <soapenv:Header/>
   <soapenv:Body>
      <tem:UpdateClearStarOrderInfo>
         <tem:BOID>x</tem:BOID>
         <tem:CustID>x</tem:CustID>
         <tem:UserName>x</tem:UserName>
         <tem:Password>x!</tem:Password>
         <tem:DonorID>x</tem:DonorID>
         <tem:ProfileID>x</tem:ProfileID>
         <tem:OrderID>x</tem:OrderID>
      </tem:UpdateClearStarOrderInfo>
   </soapenv:Body>
</soapenv:Envelope>

Expected Response Payload:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <UpdateClearStarOrderInfoResponse xmlns="http://tempuri.org">
         <UpdateClearStarOrderInfoResult>
            <UpdateClearStarOrderInfo xmlns="">
               <ErrorStatus>
                  <Code/>
                  <Type/>
                  <Message/>
               </ErrorStatus>
               <Result>X</Result>
            </UpdateClearStarOrderInfo>
         </UpdateClearStarOrderInfoResult>
      </UpdateClearStarOrderInfoResponse>
   </soap:Body>
</soap:Envelope>

What I changed the response to:

  <s:element name="UpdateClearStarOrderInfoResponse">
    <s:complexType>
      <s:sequence>
        <s:element name="UpdateClearStarOrderInfoResult">
          <s:complexType>
            <s:sequence>
              <s:element name="UpdateClearStarOrderInfo">
                <s:complexType>
                  <s:sequence>
                    <s:element name="ErrorStatus">
                      <s:complexType>
                        <s:sequence>
                          <s:element name="Code" type="s:int"></s:element>
                          <s:element name="Type" type="s:string"></s:element>
                          <s:element name="Message" type="s:string"></s:element>
                        </s:sequence>
                      </s:complexType>
                    </s:element>
                    <s:element name="Result" type="s:string"></s:element>
                  </s:sequence>
                </s:complexType>
              </s:element>
            </s:sequence>
          </s:complexType>
        </s:element>
      </s:sequence>
    </s:complexType>
  </s:element>
5
  • 1
    Is it possible to share the full WSDL? You can change the endpoint URLs if you want. Sep 20, 2016 at 20:39
  • @DanielBallinger The endpoint issue was easy to fix. It was the other two items, mainly #3, that created issues. Here's the vendors published WSDL for the example I used: widget.webccf.com/service/ClearStarOrderInfo.asmx?wsdl They have another larger and more complex WSDL that relates to this integration, but I figure that if I can solve this one, I can apply the logic to the bigger WSDL. Sep 21, 2016 at 13:59
  • Also looking at building out my own SOAP services in Apex, bypassing the WSDL entirely. Sep 21, 2016 at 14:00
  • The FuseIT SFDC Explorer can generate the raw HTTP Request and Response parsing code if that helps. I'll have a look at the WSDL soon to see about the conflicting request/response types. Sep 21, 2016 at 20:51
  • What version of the FuseIT SFDC Explorer are you using? I'm checking against your sample WSDL in the latest version and it splits the response into UpdateClearStarOrderInfoResponse_element and UpdateClearStarOrderInfoResponse_UpdateClearStarOrderInfoResult_element classes. Sep 25, 2016 at 19:27

1 Answer 1

1

In the end, I gave up trying to fix the vendor-supplied WSDL. A very kind and talented developer gave me his code that used an HTTPRequest in apex to submit a soap call. It's something I had experimented with in the past, but never got very far.

The key to building your own "soap" calling logic from within Apex, without using a WSDL is to build the request properly. I used SoapUI to test each of the WSDL's and soap calls outside of Salesforce. That would give me the exact SOAP header/body structure to use within the code to ensure the call was structured correctly. Below is some of the I used to make this possible

public static final String SOAP_ACTION_PREFIX = 'http://clearstar.net/Gateway/Profile/';
private HttpRequest createSoapRequest(string method) {
        HttpRequest soapRequest = new HttpRequest();
        soapRequest.setMethod('POST');
        soapRequest.setEndpoint(settings.EndPoint__c);
        soapRequest.setHeader('SoapAction', SOAP_ACTION_PREFIX + method);
        soapRequest.setHeader('Content-Type', 'text/xml;charset=UTF-8');
        soapRequest.setHeader('Accept-Encoding', 'gzip,deflate');
        soapRequest.setTimeout(120000); // two-minute time-out

        String xmlBody = buildCallRequestBody(method);
        soapRequest.setBody(xmlBody);

        System.debug(LoggingLevel.Error, '## soapRequest=' + soapRequest);
        System.debug(LoggingLevel.Error, '## soapBody=' + xmlBody);

        return soapRequest;
    }

public String buildCallRequestBody(String method) {

    // initial part of the soap header for the appropriate
    String xmlBody = '<soapenv:Envelope ' +
        'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" ' +
        'xmlns:prof="http://clearstar.net/Gateway/Profile">' +
        '<soapenv:Header/>' +
        '<soapenv:Body>;

    // YOUR LOGIC TO STRUCTURE THE XML BODY WILL GO HERE

    xmlBody += '</soapenv:Body></soapenv:Envelope>';

    return xmlBody;
}

The response will typically be a XML structure that you can parse using any number of mechanisms within Apex.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .