Jan.24

Connector for Dynamics Crashing When Trying to Open a Map

I was recently trying to use the Connector for Dynamics, which is a tool provided by Microsoft to provide a way to integration the various Dynamics software products. In my situation, I was trying to integrate Dynamics CRM to Dynamics AX 2012 R3.

After installing the Connector and configuring the AX and CRM adapters, I began trying to activate the maps in the recommended order which is (taken from the Connector setup guide):

  1. Map enumerated values
  2. Map employees and ERP system users
  3. Map unit schedules and unit groups
  4. Map currency information
  5. Map items and products
  6. Map customers and accounts
  7. Map contact information
  8. Map sales orders
  9. Map sales invoices

Steps 1-4 ran successfully. However, when I would try to open (not yet run) the map for step 5, the Windows service that sits behind the Connector client would stop responding and crash which would cause the client to shut down.

I tried every debugging process I could think of.

  • Turning on verbose logging for both the client and the service.
  • Examining the resulting entries in the server’s Event log.
  • Attaching WinDBG to the Windows service process and examining the output when recreating the error.
  • Running Fiddler to see if the crash was the result of an error in the network traffic (i.e. the CRM adapter had a problem).
  • Scouring the internet, blogs and Dynamics forums for AX and CRM
    • I even posted to the CRM and AX community forms, but had no answers or even responses.

At a complete standstill, I had to choice to open a MS Support ticket. The engineer mentioned that the Connector does not support self-referencing relationships on CRM entities. In our CRM instance, a self-referencing 1:N relationship on the Product entity.

After performing some testing, against an OOTB/un-customized CRM organization, I found that this was indeed the problem that was causing the Connector’s Windows Service to crash. Basically, the self-referencing relationship was causing the Connector to become stuck in an infinite loop which, in turn, caused a stack-overflow and the subsequent crash.

The recommended course of action was to remove the relationship and it’s related fields. However, due to circumstances beyond my control, I wasn’t able to do that.

I asked if the Microsoft team responsible for the Connector would consider updating the Connector to support a self-referencing relationship. After all, it’s a supported customization in CRM. The reply was since the Connector is deprecated (no longer supported after CRM 2016; versions 8.0 and 8.1), the requested change wasn’t going to happen. (There is a new integration tool being released for Dynamics 365 (version 8.2)).

In the end, I was able to find a solution on my own. I found the XML files that contained the meta-data defining the CRM entities which had been configured in the Connector for integration between AX and CRM. These XML files are located on the server where the Connector is installed: C:\Program Files (x86)\Microsoft Dynamics\Microsoft Dynamics Adapter\Adapters\Microsoft.Dynamics.Integration.Adapters.Crm2011\ObjectConfig\(yourCRMOrgName).

I had to remove two lines from the “ProductObjectProvider” file: the line referencing the relationship and the line referencing the field related to the relationship. Once the XML file was edited, I was able to open the Items to Products map in the Connector and run it as needed.

While this solution works and allows you to get around the deficiency in the Connector, there are some caveats to the solution.

  • Any time you connect the Connector to a new CRM organization (i.e. deploy the integration to test or production), you’ll have to remember to manually edit the XML file.
  • Any time you reconfigure the CRM adapter within the Connector, you’ll need to edit the XML file again.
Dynamics CRM

Apr.06

Using Javascript to Interact with Microsoft Dynamics CRM 2011

One of the ways you can extend Microsoft Dynamics CRM is to perform CRUD (create, read, update and delete) operations via the REST API or the SOAP API. This allows you to interact with the data within CRM with just HTML and Javascript. I recently had a project where I needed to create dialogs for the user to process records but the out-of-the-box CRM dialogs didn’t fit the bill. I was able to build out simple, light-weight and fast dialogs that allowed the user do what they needed to do.

Below are several examples of retrieving data from CRM, changing the Status (statecode) and Status Reason (statusreason) fields and associating Many-To-Many records. These examples are using the version of the Javascript SDK that relies on jQuery. Microsoft provides a version that does not rely on jQuery if you’re unable to use jQuery. ┬áThese examples where for Dynamics CRM 2011 but should point you in the right direction if you’re using CRM 2013 or 2014.

Retrieving Data

The following code allows you to retrieve multiple records from a given entity.

SDK.JQuery.retrieveMultipleRecords(
    'entityname',
    'var options = "$select=Name',
    function (values) {
        //OnSuccess callback
    },
    function (error) {
        //OnError callback
    },
    function () {
        //Fires once all data pages have been retrieved.
    });

The filter can be tweaked to match how you are trying to retrieve values. For example, the following filter is matching the School ID value, the Student Name ID value, the Degree optionset value and the Status (statecode) value. This filter would just replace ‘var options = “$select=Name’ in the above example. You can test your filter strings by hitting the OData service over a browser and examining the results.

"$filter=pt_School/Id eq (Guid'" + schoolId + "') and pt_StudentName/Id eq (Guid'" + studentId + "') and pt_Degree/Value eq " + degreeValue + " and statecode/Value eq 0"

 

Creating Records

The process to create a record looks somewhat similar to retrieving records. However, we create a simple Javascript object to contain the field values for the new record and pass that into the createRecord call.

There are a couple things to note here:

  1. Make sure that the names of the object’s properties match the schema names of the fields you’re populated on the entity.
  2. If you’re trying to set the value of an Optionset field, use the numerical value that CRM assigned to the option.
var myNewRecord= {};
historyRecord.name = 'John';
historyRecord.description = 'This is my description';
historyRecord.fieldA = 'Contents for FieldA';
historyRecord.fieldB = 'Contents for FieldB';

SDK.JQuery.createRecord(
    historyRecord,
    'entityname',
    function (record) {
        //OnSuccess Callback
    },
    function (error) {
        //OnError Callback
    });

Updating Records

To update an existing record, you’ll need the GUID value of the record and you’ll need to create a Javascript object just like when you create a new record. However, you only need to add the fields you’re changing to the Javascript object. Make sure that the object’s property names match the schema names of the fields.

var updatedRecord = {};
updatedRecord .FieldA = 'New value for FieldA';
updatedRecord .FieldB = 'New value for FieldB';

SDK.JQuery.updateRecord(
    currectRecordId,
    updatedRecord,
    'entityname',
    function () {
        //OnSuccess Callback
    },
    function () {
        //OnError Callback
    });

Associating Records

You can also associate records via the REST/OData API.

SDK.JQuery.associateRecords(
    "parentId",
    "parentEntityName",
    "relationshipName",
    "childId",
    "childEntityName",
    function () {
        //OnSuccess Callback
    },
    function (error) {
        //OnError Callback
});

Changing the Status and Status Reason

It is possible to change the Status (statecode) and Status Reason (statuscode) from Javascript. However, it can’t be done via the Rest/OData API. You have to build a SOAP envelope and submit it to the service at “/XRMServices/2011/Organization.svc/web”.

SDK.JQuery.SetStateRequest(
    1, //Status (statecode)
    206300005, //Status Reason (statuscode)
    'entityName', 
    currentRecordId, 
    function () {
        //OnSuccess Callback
    }
);

//Building the SOAP envelope
SetStateRequest: function (newStateCode, newStatusCode, entityName, entityId, successCallback) {
     
var requestMain = ""
requestMain += "";
requestMain += "  ";
requestMain += "    ";
requestMain += "      ";
requestMain += "        ";
requestMain += "          ";
requestMain += "            EntityMoniker";
requestMain += "            ";
//Setting Record Id Guid
requestMain += "              " + entityId + "";
//Setting Entity Name
requestMain += "              " + entityName + "";
requestMain += "              ";
requestMain += "            ";
requestMain += "          ";
requestMain += "          ";
//Setting StateCode (Status)
requestMain += "            State";
requestMain += "            ";
requestMain += "              " + newStateCode + "";
requestMain += "            ";
requestMain += "          ";
requestMain += "          ";
//Setting StatusCode (Status Reason)
requestMain += "            Status";
requestMain += "            ";
requestMain += "              " + newStatusCode + "";
requestMain += "            ";
requestMain += "          ";
requestMain += "        ";
requestMain += "        ";
requestMain += "        SetState";
requestMain += "      ";
requestMain += "    ";
requestMain += "  ";
requestMain += "";
     
var req = new XMLHttpRequest();
    
req.open("POST", "http://adm-v-dcrm01/PokagonDev/XRMServices/2011/Organization.svc/web", true)
// Responses will return XML. It isn't possible to return JSON.
req.setRequestHeader("Accept", "application/xml, text/xml, */*");
req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
//var successCallback = null;
var errorCallback = null;
req.onreadystatechange = function () { SDK.JQuery.SetStateResponse(req, successCallback, errorCallback); };
req.send(requestMain);
Dynamics CRM