Wednesday 26 November 2014

No response and catching errors cURL PHP

I covered this in another post however I thought it deserved its own "snippet". I use cURL when connecting to CRM's SOAP service as I found it easy to use almost right away.

Because I could use it right away I didn't really spend anytime thinking about it. That was until code that had been working for months suddenly stopped. I received no response from the service but I couldn't figure out why.

The investigation led me to the following function:
 public static function GetSOAPResponse($url, $request) {
    // Set up headers.
    $headers = array(
      "POST " . "/Organization.svc" . " HTTP/1.1",
      "Host: yourorganisation.api.crm5.dynamics.com",
      'Connection: Keep-Alive',
      "Content-type: application/soap+xml; charset=UTF-8",
      "Content-length: " . strlen($request),
    );
 
    $cURLHandle = curl_init();
    curl_setopt($cURLHandle, CURLOPT_URL, $url);
    curl_setopt($cURLHandle, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($cURLHandle, CURLOPT_TIMEOUT, 60);
    curl_setopt($cURLHandle, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($cURLHandle, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($cURLHandle, CURLOPT_SSLVERSION, 3);
    curl_setopt($cURLHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    curl_setopt($cURLHandle, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($cURLHandle, CURLOPT_POST, 1);
    curl_setopt($cURLHandle, CURLOPT_POSTFIELDS, $request);
    $response = curl_exec($cURLHandle);
    curl_close($cURLHandle);
 
    return $response;
  }

In such a small project such as this when something stops working the question is usually what dependencies have changed? I presumed something at the Microsoft end (I was using CRM Online) had changed but the question was what.

A quick Google search on curl_exec shows that it does not throw exceptions due to it being a C library all wrapped up. So in order to get an exception you need to instead use the following:
if( ! $response = curl_exec($cURLHandle)) 
   { 
       trigger_error(curl_error($cURLHandle)); 
   }

This will fire off a PHP exception for the cURL error. Which led me to my real issue!

Microsoft due to the 'poodle' vulnerability in SSL updated to SSL version 4. The code I had above (grabbed from some other persons post presumably!) has the SSL Version explicitly stated. By changing this to 4 the issue went away. However I thought it was easier to just remove that setting and this seemed to do the trick (and hopefully makes it a bit more robust for future use!). So the updated code is below.

public static function GetSOAPResponse($url, $request) {
   // Set up headers.
   $headers = array(
     "POST " . "/Organization.svc" . " HTTP/1.1",
     "Host: yourorganisation.api.crm5.dynamics.com",
     'Connection: Keep-Alive',
     "Content-type: application/soap+xml; charset=UTF-8",
     "Content-length: " . strlen($request),
   );
 
   $cURLHandle = curl_init();
   curl_setopt($cURLHandle, CURLOPT_URL, $url);
   curl_setopt($cURLHandle, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($cURLHandle, CURLOPT_TIMEOUT, 60);
   curl_setopt($cURLHandle, CURLOPT_SSL_VERIFYPEER, FALSE);
   curl_setopt($cURLHandle, CURLOPT_FOLLOWLOCATION, TRUE);
   curl_setopt($cURLHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
   curl_setopt($cURLHandle, CURLOPT_HTTPHEADER, $headers);
   curl_setopt($cURLHandle, CURLOPT_POST, 1);
   curl_setopt($cURLHandle, CURLOPT_POSTFIELDS, $request);
   if( ! $response = curl_exec($cURLHandle)) 
   { 
       trigger_error(curl_error($cURLHandle)); 
   }
   curl_close($cURLHandle);
 
   return $response;
 }

Wednesday 12 November 2014

CRM 2011 Workflow execution

As newer versions of CRM are released I find myself wondering when we might reach a point where plugin code might not be required. Between Workflows, JavaScript, and Business Rules CRM it is getting easier to customize in more and more powerful ways.

Every time I think of this though I find a "gotcha" which makes me realise plugin code will still be required for a while yet.

We had an issue where the client told us that there was a bug with auditing in CRM 2011. The problem was two different sets of audit changes were listed.

The problem ended up being not with the auditing but with the workflows. Workflows do not capture data at the time of change rather they run against the data at time of workflow execution. This is a rather obvious but interesting difference.

In our case the record needed to be recommended and then approved. We had a workflow which was created and run on "Status" change that on Approval would push data to a new entity . In a real world scenario we would presume that no one would recommend and immediately approve however there would be many cases I’m sure where a fast change such as this is completely possible.

Where a fast change like this occurs chances are that 1) the workflow has not yet been created by CRM yet or 2) the workflow has been created and not run. The issue of course is the workflow will look at the Status and see "Approved" both times it runs!

So if you have a field that is updated multiple times in quick succession I suggest having a plugin (which snapshots that data) rather than relying on a workflow.

NOTE: I haven't confirmed this in 2013 or 2015 so they might actually handle snapshots in workflows? The above talks about CRM 2011 specifically.