Thursday, September 24, 2015

Salesforce Winter `16 breaking SOAP Partner API changes

Just encountered this connecting to a Winter `16 Sandbox Org (v35.0) via the SOAP Partner API from Summer `15 (v34.0).

I've cross posted to the Salesforce StackExchange and raised support case 12544039

System.InvalidOperationException: There is an error in XML document (1, 2239646). ---> System.InvalidOperationException: Instance validation error: 'urn:SearchLayoutFieldsDisplayed' is not a valid value for soapType.
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read2427_soapType(String s)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read2428_Field(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read2458_DescribeSObjectResult(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read2692_describeSObjectsResponse()
   at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer193.Deserialize(XmlSerializationReader reader)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at FuseIT.G4S.SalesforceConnector.SalesforcePartner.SforceService.describeSObjects(String[] sObjectType)

I suspect the problem is the new soapType's that were added in API version 35.0 for Winter `16.

As they didn't exist in v34.0 of the API, if they come back in the SOAP response the .NET XML Serialization won't know how to handle them.

The following API call against v34.0 of the Partner API shows the problem.

Request

To: https://cs5.salesforce.com/services/Soap/u/34.0/00DO00000000001

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:partner.soap.sforce.com">
   <soapenv:Header>
      <urn:SessionHeader>
         <urn:sessionId>00DO00000000001!AQYAQKme4PP0v_FURhdtYVACcTF6vsvw_NOTmyREALsessionId_8irB66snPfNb9MLrSDB7dT95YvZA8hFVFD63cyt</urn:sessionId>
      </urn:SessionHeader>
   </soapenv:Header>
   <soapenv:Body>
      <urn:describeSObjects>
         <urn:sObjectType>SearchLayout</urn:sObjectType>
      </urn:describeSObjects>
   </soapenv:Body>
</soapenv:Envelope>

Response Snippet

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="urn:partner.soap.sforce.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Header>
      <LimitInfoHeader>
         <limitInfo>
            <current>39</current>
            <limit>5000000</limit>
            <type>API REQUESTS</type>
         </limitInfo>
      </LimitInfoHeader>
   </soapenv:Header>
   <soapenv:Body>
      <describeSObjectsResponse>
         <result>
           
     <!--SNIP-->
   
            <fields>
               <autoNumber>false</autoNumber>
               <byteLength>0</byteLength>
               <calculated>false</calculated>
               <caseSensitive>false</caseSensitive>
               <createable>false</createable>
               <custom>false</custom>
               <defaultedOnCreate>false</defaultedOnCreate>
               <deprecatedAndHidden>false</deprecatedAndHidden>
               <digits>0</digits>
               <filterable>false</filterable>
               <groupable>false</groupable>
               <idLookup>false</idLookup>
               <label>Fields Displayed</label>
               <length>0</length>
               <name>FieldsDisplayed</name>
               <nameField>false</nameField>
               <namePointing>false</namePointing>
               <nillable>true</nillable>
               <permissionable>false</permissionable>
               <precision>0</precision>
               <queryByDistance>false</queryByDistance>
               <restrictedPicklist>false</restrictedPicklist>
               <scale>0</scale>
               <soapType>urn:SearchLayoutFieldsDisplayed</soapType>   
               <!-- ^^^ PROBLEM IS HERE for v34.0 - this isn't a valid soapType until v35.0 -->
               <sortable>false</sortable>
               <type>complexvalue</type>
               <unique>false</unique>
               <updateable>false</updateable>
            </fields>
   
            <!--SNIP-->
               
            <keyPrefix>4co</keyPrefix>
            <label>Search Layout</label>
            <labelPlural>Search Layouts</labelPlural>
            <layoutable>false</layoutable>
            <mergeable>false</mergeable>
            <name>SearchLayout</name>
            <queryable>true</queryable>
            <replicateable>false</replicateable>
            <retrieveable>false</retrieveable>
            <searchable>false</searchable>
            <undeletable>false</undeletable>
            <updateable>false</updateable>
            <urlDetail xsi:nil="true"/>
            <urlEdit xsi:nil="true"/>
            <urlNew xsi:nil="true"/>
         </result>
      </describeSObjectsResponse>
   </soapenv:Body>
</soapenv:Envelope>

Ideally Salesforce shouldn't be sending elements from the v35.0 back to the v34.0 API. It's likely that SearchLayoutField, SearchLayoutButtonsDisplayed, SearchLayoutButton and RecordTypesSupported would cause similar issues with existing integrations.

Bonus namespace alterations

Be aware that some elements have changed namespace between v34.0 and v35.0. E.g. In v34.0 the soapType enumerations location and address were in the urn namespace ("urn:partner.soap.sforce.com"). In v35.0 They are now in the tns namespace (xmlns:tns="urn:partner.soap.sforce.com"). Make sure the API URL you are calling matches up with the WSDL version the classes were generated from.