3

I've been trying to get a webservice callout working by parsing it with wsdl2apex and constructing it with that method. Callouts are failing because of errors in the constructed XML which causes an exception to be thrown on the receiving end. I've narrowed it down to namespace issues, namely that the endpoint expects that one of the elements in the xml should have a namespace, which it doesn't when I inspect the xml being sent in my developer org via Developer Console.

This is a part of the SOAP service being referenced:

<xs:complexType name="faultReport">
<xs:sequence>
<xs:element name="serviceNumber" form="unqualified" type="xs:int"/>
<xs:element name="customerID" form="unqualified" type="xs:string" minOccurs="0"/>
<xs:element name="customerName" form="unqualified" type="xs:string" minOccurs="0"/>
<xs:element name="customerContact" form="unqualified" type="tns:contact" minOccurs="0"/>
<xs:element name="operatorContact" form="unqualified" type="tns:contact" minOccurs="0"/>
<xs:element name="description" form="unqualified" type="xs:string" minOccurs="0"/>
<xs:element name="measurement" form="unqualified" type="xs:string" minOccurs="0"/>
<xs:element name="origin" form="unqualified" type="xs:string" minOccurs="0"/>
<xs:element name="afterHours" form="unqualified" type="xs:string" minOccurs="0"/>
<xs:element name="user" form="unqualified" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>

This is my generated class:

 public class fault {
        public String customerSSN;
        public String customerName;
        public WSGateWay_Milatypes.contact customerContact;
        public WSGateWay_Milatypes.contact operatorContact;
        public WSGateWay_Milatypes.resolution resolution;
        public String origin;
        public DateTime closed;
        public String measurement;
        public WSGateWay_Milatypes.noteList notes;
        private String[] customerSSN_type_info = new String[]{'customerSSN','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] customerName_type_info = new String[]{'customerName','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] customerContact_type_info = new String[]{'customerContact','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] operatorContact_type_info = new String[]{'operatorContact','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] resolution_type_info = new String[]{'resolution','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] origin_type_info = new String[]{'origin','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] closed_type_info = new String[]{'closed','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] measurement_type_info = new String[]{'measurement','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] notes_type_info = new String[]{'notes','http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://xxxx.xx/GateWay/XSD/Mila/MilaTypes/v1.0','true','false'};
        private String[] field_order_type_info = new String[]{'customerSSN','customerName','customerContact','operatorContact','resolution','origin','closed','measurement','notes'};
    }

This is my generated class for the Contact object, which is referenced in the class:

public class contact {
        public String name;
        public String number_x;
        private String[] name_type_info = new String[]{'name','http://xxxxx.xx/Gateway/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] number_x_type_info = new String[]{'number','http://xxxxx.xx/Gateway/XSD/Mila/MilaTypes/v1.0',null,'0','1','false'};
        private String[] apex_schema_type_info = new String[]{'http://xxxx.xx/Gateway/XSD/Mila/MilaTypes/v1.0','true','false'};
        private String[] field_order_type_info = new String[]{'name','number_x'};
    }

My callout class then creates a stub from the webservice definition and makes the callout:

This is my example constructed callout, taken from the Developer Console logs:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header/>
<env:Body>
    <faultReportRequest xmlns="http://xxxx.xx/Gateway/XSD/WebServices/FaultService/v1.5">
    <fault>
        <serviceNumber xmlns="">1234567</serviceNumber>
        <customerID xmlns="">302</customerID>
        <customerContact xmlns="">
            <name>Contact 1</name>
            <number>8629001</number>
        </customerContact>
        <operatorContact xmlns="">
            <name>Contact 2</name>
            <number>8629001</number>
        </operatorContact>
        <description xmlns="">something</description>
        <measurement xmlns="">measure</measurement>
        <origin xmlns="">Test</origin>
        <afterHours xmlns="">false</afterHours>
        <user xmlns="">Admin</user>
    </fault>
</faultReportRequest>
</env:Body>
</env:Envelope>

The problem is that the name and number elements under the Contact element should have a declared namespace, but they don't and instead the Contact element has a declared namespace, which it shouldn't. Can anyone shine a light on this, what string values I need to change to make this:

<customerContact xmlns="">
                <name>Contact 1</name>
                <number>8629001</number>
            </customerContact>

into this:

<customerContact xmlns="">
            <name xmlns="http://xxxx.xx/Gateway/XSD/WebServices/FaultService/v1.5">Contact 1</name>
            <number xmlns="http://xxxx.xx/Gateway/XSD/WebServices/FaultService/v1.5">8629001</number>
        </customerContact>

?

Using HTTPRequest to do this

Is it perhaps more feasible to do this by hand constructing the XML and making a HTTPrequest to the endpoint? It would be infinately easier, but my tests have all failed, since ehen I set the request endpoint as the endpoint referenced in the WSDL, it fails with a 'endpoint not found' error. Are there any huge gotchas with using that approach?

Edit

I'd like to add that I gave up on this eventually and had a REST based service created for me, and it took me all of 1 hour to get the connection to that up and running. Since Apex has a well documented and robust support for that I'd steer anyone in that direction if possible and avoid SOAP based integrations unless nothing else is available.

  • On your last point about using HttpRequest, here is something I wrote several years ago on that subject force201.wordpress.com/2010/05/20/…. – Keith C May 19 '14 at 5:14
  • Yes, I read that post in my search for solutions to my problem. Using the usual HTTPRequest way sounds feasible but I'll have to find out why my calls are failing when I use a HTTPReq and set the endpoint to the endpoint given in the WSDL, and set the method as 'POST'. – akarnid May 19 '14 at 8:58
  • An intern and myself have been working on an alternative to wsdl2apex that should generate compatible code and/or the HTTPRequest. If it doesn't work, are you able to share the WSDL with us? – Daniel Ballinger May 19 '14 at 20:12
  • Thanks for that Daniel. I'll make sure to try this tool tommorrow. I can most certainly share the WSDL, since most of the endpoints in it are behind firewalls anyway. – akarnid May 20 '14 at 0:22
  • @DanielBallinger - I've tried this SFDC Explorer tool with its wsdl2apex integration, but I'm unable to create classes with it using Windows 8.1 - Error is : ApexClasses were not generated. Original error: The given key was not present in the dictionary. Do I get support via the FuseIT website for this? Interesting tool, want to get it to work. – akarnid May 20 '14 at 14:12
1

I worked with your WSDL and found out that it has <xsd:extension base="tns:Sample"> element in it which Salesforce.com does not handle. It is based on inheritance. We have uploaded a new version of SFDC Explorer (v1.3), which will now be able to parse and generate Apex classes with your WSDL.

After deploying the generated classes to Salesforce.com and when trying to invoke web service this is what the SOAP Request message looked like:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <env:Header />
  <env:Body>
    <faultReportRequest xmlns="http://siminn.is/MilaGateway/XSD/WebServices/FaultService/v1.5">
      <fault>
        <serviceNumber xmlns="http://siminn.is/MilaGateway/XSD/Mila/MilaTypes/v1.0">1</serviceNumber>
        <customerID xmlns="http://siminn.is/MilaGateway/XSD/Mila/MilaTypes/v1.0">xyz</customerID>
        <customerContact xmlns="http://siminn.is/MilaGateway/XSD/Mila/MilaTypes/v1.0">
          <name>bla</name>
          <number>bla</number>
        </customerContact>
      </fault>
    </faultReportRequest>
  </env:Body>
</env:Envelope>

I don't think <name> and <number> need namespace because they are strings according to the WSDL. They will take the namespace from their parent element.

  • 1
    Unfortunately it matters to the SOAP based service. The <name> and <number> elements need to have namespaces declared. Skip them and you run into validation errors. – akarnid May 26 '14 at 18:31
  • According to the WSDL it does not matter because <xs:complexType name="contact" defines <name> and <number> and complex type "contact" is in schema with targetNamespace "siminn.is/MilaGateway/XSD/Mila/MilaTypes/v1.0" and "customerContact" is of type "contact" and its namespace is defined. Moreover child elements will get their namespace from the parent element. – Girisha May 29 '14 at 23:38
1

For anyone who is wondering, I eventually gave up on trying to shoehorn this into auto-generated Apex classes (although I discovered the excellent SFDC Explorer tool . In the end, I managed to get the IT team to create a REST-based version of the service and it took me only a short while to use HTTPRequest/HTTPResponse classes to integrate it easily into my org.

So unfortunately i wasn't able to see this through to the end, although I'll happily discuss the pros & cons of SOAP based integrations with Salesforce :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.