Adventures with Microsoft.Xrm.Tooling in Microsoft Dynamics 365 Customer Engagement

By | June 27, 2017

Microsoft.Xrm.Tooling.Connector library has been made available by the Dynamics CRM SDK team to make it easy to perform common operations, using direct functions that have been exposed for these.

Exploring the library in came in with a learning experience with subtle differences in how we were used to doing it earlier using API libs available.

Establishing Connection:

First things first, establishing connection. I had created a sample project a few months back that was perfectly working back then. However, when we tried to execute the same package again, we received the following error.

“Unable to Login to Dynamics CRMOrganizationServiceProxy is nullOrganizationServiceProxy is nullOrganizationWebProxyClient is nullOrganizationServiceProxy is nullOrganizationWebProxyClient is nullOrganizationServiceProxy is null”

Adventures with Microsoft.Xrm.Tooling in Microsoft Dynamics 365 Customer EngagementWe found an article by Aileen at, however make the requested change did not resolve the problem in our case.

Then to make sure we were working on the latest version of the libraries, we deleted the references to the following libraries

  • Xrm.Sdk.dll
  • Crm.Sdk.Proxy.dll
  • Xrm.Sdk.Deployment.dll
  • Xrm.Tooling.Connector.dll
  • IdentityModel.Clients.ActiveDirectory.dll

When you compile, it works just fine, but upon execution, you receive an error about missing reference to Microsoft.IdentityModel

Adventures with Microsoft.Xrm.Tooling in Microsoft Dynamics 365 Customer EngagementYou need to add references to the following to get this to work

  • Xrm.Tooling.Connector.dll
  • Xrm.Sdk.Deployment.dll
  • IdentityModel.Clients.ActiveDirectory.dll

Creating Records:

Traditionally, service.create has always required an object of Entity class as a parameter to be passed. XRM.Tooling, provides an additional way to pass the details of the record. You can now pass them as a dictionary of key/value pair

//create the dictionary array
 Dictionary<string, CrmDataTypeWrapper> data = new Dictionary<string, CrmDataTypeWrapper>();
 data.Add("name", new CrmDataTypeWrapper("Test data " + DateTime.Now.ToString(), CrmFieldType.String));
 data.Add("address1_city", new CrmDataTypeWrapper("Mumbai", CrmFieldType.String));
 data.Add("telephone1", new CrmDataTypeWrapper("905-555-5555", CrmFieldType.String));
 //create the record
 Guid id = client.CreateNewRecord("account", data);


Setting field values for CrmDataTypeWrapper

In CRM 4 days we used to have the wrapper classes for data type that we needed to create object of set the values for. So a Boolean value could be set by creating an object of CrmBoolean() and then set the value of that object to true/false as desired. Looks like this system is back with the tooling connector.

Here is how to set the values for the various data types

1. Customer:

//Set the customerid 
       CrmDataTypeWrapper cust = new CrmDataTypeWrapper();
       cust.ReferencedEntity = "account";
       cust.Value = accId;
       cust.Type = CrmFieldType.Customer;

 2. String:

//Set the name - String Field
CrmDataTypeWrapper name = new CrmDataTypeWrapper("Sample quote " + DateTime.Now.ToString(), CrmFieldType.String);

 3. Boolean:

//Set write-in
CrmDataTypeWrapper isproductoverridden = new CrmDataTypeWrapper(true, CrmFieldType.CrmBoolean);

 4. PickList:

    //Set the status field
	quoteDataArray["statuscode"] = new CrmDataTypeWrapper((int)(4), CrmFieldType.Picklist);

5. Numeric:

detailArray["quantity"] = new CrmDataTypeWrapper((decimal)(10), CrmFieldType.CrmDecimal);

6.  Money:

//Set the price
detailArray["priceperunit"] = new CrmDataTypeWrapper((decimal)(15.5), CrmFieldType.CrmMoney);

7. Guid/Unique Identifier:

Guid quoteID = Guid.NewGuid();
        CrmDataTypeWrapper id = new CrmDataTypeWrapper(quoteID, 	CrmFieldType.UniqueIdentifier);

 8. Lookup:

//Set the pricelist 
      CrmDataTypeWrapper pricelevel = new CrmDataTypeWrapper();
      pricelevel.ReferencedEntity = "pricelevel";
      pricelevel.Value = new Guid("XXXBE2B-B44F-E711-80DE-000D3AF32500");
      pricelevel.Type = CrmFieldType.Lookup;


Batch Processing:

To ensure that all the requests are executed in a transaction so that even if a single request fails, the entire transaction rolls back, it provides a way for Batch Execution of requests as well.

The first step is to generate a Batch Id or Name

//Create a batch for commit/rollback scenario
Guid batchID = client.CreateBatchOperationRequest("quotebatch", true, false);

Next with every request submitted, please provide the batchid along

//Create the Quote record
client.CreateNewRecord("quote", quoteArray, batchId: batchID);

//Create quote line record  
client.CreateNewRecord("quotedetail", detailArray, batchId: batchID);

Though these requests get added to the batch, they have not executed right away. You need to make the call to execute the batch for the requests in the batch to be processed.

//Execute batch

ExecuteMultipleResponse response = client.ExecuteBatch(batchID);

 If the response.IsFaulted == false that means the records have been successfully created successfully.

You get the results of the executed requests in the response object as can be seen below

Adventures with Microsoft.Xrm.Tooling in Microsoft Dynamics 365 Customer EngagementSpecial Requests:

Special requests like CloseQuote that earlier had to be executed through ExecuteRequest are now directly available as a function in the library that can be invoked directly

//Connect to CRM
 CrmServiceClient client = new Microsoft.Xrm.Tooling.Connector.CrmServiceClient(connString);

 //Create a batch for commit/rollback scenario
 Guid quotebatchID = client.CreateBatchOperationRequest("quotebatch", true, false);

 //Create the dictionary to define the list of fields that needs to be updated
 Dictionary<string, CrmDataTypeWrapper> quoteDataArray = new Dictionary<string, CrmDataTypeWrapper>();

 //Set the status field as Active 
 quoteDataArray["statuscode"] = new CrmDataTypeWrapper((int)(4), CrmFieldType.Picklist);

Note: The status must be greater than 3 but less than or equal to 7. You can also refer to the Microsoft’s blog for more info on this.

//quoteDataArray is the object of the Dictionary used to update the status to activate
//So basically we are closing the Quote as Active
client.CloseQuote(new Guid("7ECAC454-DA27-42F3-B168-A1E0C11FA792"), quoteDataArray, batchId: quotebatchID);

//Get the response of the CloseQuote request 
ExecuteMultipleResponse quoteResponse = client.ExecuteBatch(quotebatchID);

Click2Clone - Copy/clone Microsoft Dynamics CRM/Dynamics 365 records