Integrate with Dynamics CRM Online using Web API

Integrate with Dynamics CRM Online using Web API

Sunny Sun lol

Build a REST service layer as an integration point to CRM

Why integration

The Enterprise Information System is like modern warfare, both are composed of highly sophisticated elements. In the modern battlefield, simply adding new weapons like stealth aircraft can not win a war, situational awareness with information sharing, and collaboration between military assets from ballistic missile submarines to special forces on the ground is the “game changer”. In the current business environment, to gain an edge, just implementing a top-rank application like Dynamics CRM is not enough, the key is to collaborate with vital business data to help business users to make informed decisions.

In military terms, it is called “Network Centric Warfare”, in Business, it is called Integration.

Integration with CRM

Recently I have been working on a project to integrate Dynamics CRM into an Enterprise Service Bus system. I found the process of integration to CRM as a whole is not well documented for beginners, the purpose of this article is to share my experience in building a REST service layer as an integration point to CRM 2016.

Scenario

To illustrate the integration process, let’s assume a company recently implemented Dynamics CRM 2016. The sales team wants to integrate an enterprise mobile app with CRM. The Mobile app will retrieve client contacts from CRM, so salesmen can contact the client. Salesmen may also post new leads to CRM. After the lead is posted, the default workflow will be activated to process the lead.

The Solution

The above scenario requires the mobile app to retrieve data from and write data to CRM. A REST service layer is introduced to provide a facade to CRM Web API. By using the REST layer as the integration point, we encapsulate the details of connecting to Web API, thus if there is any change in the future version of CRM, the REST service is the only place that needs to be updated.

The canonical data model is applied in the REST Service layer to provide a common data format. The following code snippet illustrates this approach with the leads entity data model.

   /// <summary>
   /// a common lead data format to all consumer apps
   /// </summary>
    public class LeadDto
    {
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public string PhoneNumber { get; set; }
    }
    /// <summary>
    /// Lead data model used to posted to CRM web api
    /// </summary>
    public class CRMLeadModel
    {
        public string firstname { get; set; }
        public string middlename { get; set; }
        public string lastname { get; set; }
        public string telephone1 { get; set; }
    }

Dynamics Server-to-Server (S2S) Authentication

The REST service needs to authenticate to CRM first before it can connect to Web API, S2S is used because it is secure and doesn’t need to use a paid Dynamics 365 user license. As illustrated in the diagram below, an application user account is created and associated with a custom security role, rather than user credentials, the application is authenticated based on a service principal identified by an Azure AD Object ID value which is stored in the created application user account. Please note that S2S authentication is only available to CRM Online.

CRM 2016 S2S AuthenticationCRM 2016 S2S Authentication

Setup S2S

Registering the App in Azure to get ClientID and Client Secret

  1. Add a new application registration in Azure portal with your Dynamics CRM subscription. After saving, a new Application ID should be shown.
  2. Select the registered app just created, add new Settings/Key and copy the value of the Key
  3. Go to Required Permissions, Add “Dynamics CRM online” and tick “Access CRM online as organisation users”

After completing the above steps, you should have the following keys

  • ApplicationID(ClientID): generated in Step 1

  • Client Secret: generated in Step 2

  • TenantID: go to Azure Active Directory -> Properties -> Directory ID

  • AADInstanceUrl: https://login.microsoftonline.com

  • OrganizationUrl: CRM online root Url, i.e. https://[your org name].api.crm6.dynamics.com/

    Create CRM Application User and Security Role

    1. Go to CRM > Security Roles, create a new Security Role
    2. Create a new CRM application user, and enter the Application ID obtained in the previous step. Note: Select “Application Users” before clicking on “New” button.

  1. Assign the newly created user with the custom security role created in step 1.

Now we should be able to use the ADAL Nuget package, to obtain the Access Token.

**protected** **async** Task<**string**> GetAccessToken()
{
    **var** clientcred = **new** ClientCredential(applicationId, clientSecret);
    **var** authenticationContext = **new** AuthenticationContext($"{aadInstanceUrl}/{tenantId}");
    **var** authenticationResult = **await** authenticationContext.AcquireTokenAsync(organizationUrl, clientcred);
    **return** authenticationResult.AccessToken;
  }

Read data from CRM

After obtaining the access token, it needs to be added to the HTTP request header.

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

Retrieving data from CRM is simply a Get HTTP request via OData. To retrieve a contact entity, the request looks like the one below. Please note that this example will return every field in the contact record, which is not a good practice, in real-life cases, $Select should be used to only return the data you need.

GET http://[Organization URI]/api/data/v9.0/contacts(9cdbf27c-8efb-e511-80d2-00155db07c77)

To retrieve a list of options set, the request looks like below

GET http://[ORG URI]/api/data/v9.0/
GlobalOptionSetDefinitions(Name='{OptionSetName}')

In REST Service, the Get HTTP Request is sent using HttpClient, and the response will be received and deserialized.

var client = new HttpClient();
**var** response = **await** client.GetAsync(url);
**var** result = **await** response.Content.ReadAsStringAsync();

Write Data to CRM

To create an entity in CRM, we use a POST request. The following code snippet is simplified for illustration purposes only.

CRMLeadModel leadModel = **new** CRMLeadModel()
            {
                firstname = leadDto.FirstName,
                lastname = leadDto.LastName,
                middlename = leadDto.MiddleName
            };
**var** leadUrl = $"[Organization URI]/api/data/v9.0/leads";

HttpContent content = **new** StringContent(JsonConvert.SerializeObject(leadModel), Encoding.UTF8, "application/json");
var client = new HttpClient();
**var response = await** client.PostAsync(url, content);

The response header contains the Uri of the newly created entity.

You can create multiple related entities in a single operation by defining them as navigation properties values. For example, the following Lead Entity contains an object property of the single-valued navigation property PrimaryPreference, when the Lead entity is posted, it will create a lead entity as well as Perference entity.

CRMLeadModel leadModel = **new** CRMLeadModel()
            {
                *PrimaryPreference = new CRMPreferenceModel(){
                  // populate the preference model properties
                 }
*            }*;*

Activate a Process flow in CRM

In Dynamics CRM 2016, the new “SetProcessRequest” is introduced to allow the setting of default business process flow. In this demo, after a salesman post leads to a CRM, we want to activate the default workflow associated with the Lead entity.

Firstly, to get the default workflow Id, we use the following OData call:

[ORG URI]/api/data/v9.0/workflows?$filter=primaryentity eq 'lead'

To set the BPF, two parameters: New Process and Target need to be passed to the request as the following code snippet.

**var** setProcessAction = **new** SetProcessAction();
setProcessAction.target = **new** Target()
            {
                leadid = leadId,
                odatatype = "Microsoft.Dynamics.CRM.lead"
            };
setProcessAction.newprocess = **new** NewProcess()
            {
                workflowid = wrokflowId, 
                odatatype = "Microsoft.Dynamics.CRM.workflow"
            };
 **var** qualificationUrl = $"[ORG URI]/api/data/v9.0/SetProcess";

The result of the above SetProcessRequest is that the BPF is activated for the newly created lead entity.

Devil is in the details

A few little tricks/trips that will make your integration journey easier.

CRM 2016 Web Api support OData V4, one of the very useful feature is the navigation properties which allow you to retrieve or update data associated with the current entity. In the HTTP Request Content, it needs to be used with @odata.bind annotation. For example, the “parentcontactid” field in Lead Entity is a lookup to contact entity, the JSON representation of the field in HTTP request is like below

"parentcontactid@odata.bind": "/contacts(735bea55-a421-e811-a830-000d3ae09197)"

// To serialize the JSON name with @, we need to use the JSONProperty attributes
[JsonProperty("parentcontactid@odata.bind")]

Tools

CRM REST builder is a great tool when working with Web API. It is a code generator that creates JavaScript to perform actions against CRM’s REST endpoints. It installs as a managed solution in your organization so you’ll get the benefit of working with the entities and attributes that you’ve created.
jlattimer/CRMRESTBuilder
CRMRESTBuilder - A tool for CRM 2011/2013/2015/2016/365 Online & On Premise to generate JavaScript code using the 2011…github.com

English like Plural

You may already have noticed that when querying with CRM API, you need to add “s” to the entity name. but there are exceptions, for example, anything ending in “s” is pluralized as “ses”, and “y” is pluralized as “ies”. so the following request will return a “Resource not found” error.

https://[ORG URI]/api/data/v9.0/opportunitys

The correct OData call is

https://[ORG URI]/api/data/v9.0/opportunities

Enjoy your journey in CRM integration!

If you are not already a paid member of Medium, **you can do so by visiting this link **. You’ll get unlimited full access to every story on Medium. I’ll receive a portion of your membership fees as a referral.