Tuesday, 29 December 2020

Dynamics 365 CRM Web API with Azure Function - Nail it!

As you all know there are mainly two connectivity options are available for our apps ( Azure function, Console app, mobile app, web apps etc) to communicate with Dynamics 365 CRM.

  • Organization service - SOAP service 
  • Dynamics 365 CRM Web API - HTTP REST API

Organization service has some limitations. For instance, you could only use a .Net Frame work based app with organisation service. Also in my view, it is getting less popular day by day.

Dynamics 365 CRM Web API has a lot of cool features. One of the main advantages is that you could use .Net core based apps ( for instance, azure functions, web apps etc)to connect to Dynamics CRM. Third party systems can utilise Crm Web Apis to communicate with Dynamics 365 CRM. Using a timer triggered .Net core azure function we could easily demonstrate this. Main steps are below. Detailed steps and sample code are also provided in this post.

  • How to generate a token from Azure AD for Dynamics 365 CRM Web API
  • Use the token to call a simple Dynamics CRM Web Api  - Who am I- It returns some basic info like your organizationid,userid etc

First things first , let's understand the architecture first. I have created an architecture diagram to understand this functionality. Please note that the  Azure AD and Dynamics 365 CRM are under the same tenant. 

As you could see in the diagram, Azure function requests the token from Azure AD first. Using this token it can do API calls( CRUD - Create, Read, Update and Delete operations) to Dynamics 365 CRM.  

Tokens life time: By default Azure AD tokens expire in one hour (ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-configurable-token-lifetimes#access-tokens)

Azure AD Part:

From Azure we need the below values in order to retrieve a token.

  • Tenant Id
  • Application Id
  • Client Secret

In order to get these values we need to do some configurations. These are shown in the diagram. But now let's do it step by step.

Navigate to  https://portal.azure.com/  and look for Active Directory.

 

 We get the Tenant Id straightaway as shown in the picture. That was easy! one down!
 

 

Navigate to App Registrations on the left navigation.



Click on New Registration.


Register a new application with a preferred name.

 


And we get the Application Id from here.



Next step is to set up API permission for our Dynamics 365 CRM instance. So let's navigate to API Permissions.

Click on Add a permission option.


Let's choose Dynamics CRM from the list. You could also see that other app registrations are possible here. Our focus is Dynamics CRM.


Tick on the user_impersonation option and click on Add permission. It means that this application is registered here and it can access Dynamics CRM as a user (ref:https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app)


Next step is to define a new client secret for our app registration.Click on the Certificates & Secrets option. And then click on the New Client Secret button.

It is possible to set expiry for the secret. In our case, it doen't matter. Just a description and choose the expiry as per our preference.

Now there is an important bit here. We need only Client secret value not the ID displayed there. I didn't have to use that anywhere.


Azure set up is done here. 

Dynamics CRM Part:

Next part is Dynamics 365 CRM. So we need to create a new 'application user' in Dynamics. This user is created based on the application id from the Azure App registration that we did earlier.

Navigate to Dynamics CRM->Settings->Security->Users and choose application users.


Click on the New button


Here is a tricky part. We need to make sure that we switch forms to Application user form.

Application Id - The one from Azure app registrion. Please refere previous step.

User Name, Primary Email - I usally put something like this

preferredusername@mycrmtrialorganisationname.onmicrosoft.com

For instance, testuser1@mytrialcrm.onmicrosoft.com ( Refer your trial crm login)

Full Name - As you prefer.

After providing all the above details, save the record.

If the user creation is successul, you should see Application ID URI and Azure AD Object ID auto populated.


Next step is to give access to the application user. As you could imagine, a user would need security roles in order to do CRUD ( Create, Read, Update, Delete)operations. 


So in this case let's assign system administrator role to this user.


We need one more info from Dynamics CRM. Basically we need Crm web api base url also known as service root Url. Navigate to Developer resources as shown below.


Copy the service root url. This is needed in our web api request for whoami.



I hope that you can relate all the steps with the architecture diagram now. Simple demo built on the above steps is given below. It is a simple Web API call. But you could expand it. For instance, create contact , lead etc.

Sample azure function here is based on .Net Core 3.1 and has a timer trigger of 1 minute. This means it gets triggered every minute. You could run it locally easily.

Azure functions have a settings file. It is handy to define all the config values there and retrieve when needed.

local.settings json file is here.

Oranganization url is your crm url, Aad Instance is the valuei in the below screen shot. It is a generic value.



Here is the full source code

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace AzureTimerTriggerFunD365WepApi.Core
{
    public class D365WebApiTokenDemo
    {
        private string _token;
        [FunctionName("D365WebApiTokenDemo")]
        public void Run([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log)
        {
            log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
            var tokenResponse = GenerateToken();
            _token = tokenResponse.Result;
            var whoAmI = WhoAmI();
            log.LogInformation($"Who am I? {whoAmI.Result}");

        }

        public async Task<string> GenerateToken()
        {
            var organizationUrl = Environment.GetEnvironmentVariable("OrganizationUrl");
            var aadInstance = Environment.GetEnvironmentVariable("AadInstance");

            var applicationId = Environment.GetEnvironmentVariable("ApplicationId");
            var tenantId = Environment.GetEnvironmentVariable("TenantId");
            var clientSecret = Environment.GetEnvironmentVariable("ClientSecret");


            var clientCredentials = new ClientCredential(applicationId, clientSecret);
            var authenticationContext = new AuthenticationContext(aadInstance + tenantId);
            var authenticationResult = await authenticationContext.AcquireTokenAsync(organizationUrl, clientCredentials);

            return authenticationResult?.AccessToken ?? throw new InvalidOperationException("No Token Received");
        }

        public async Task<string> WhoAmI()
        {
            var crmWebApiBaseUrl = Environment.GetEnvironmentVariable("CrmWebApiBaseUrl");
            var httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",
                _token);

            var whoAmIResponse = await httpClient.GetAsync($"{crmWebApiBaseUrl}/WhoAmI()");

            return await whoAmIResponse.Content.ReadAsStringAsync();
        }
    }
}

1 comment:

  1. Hi Dear,

    I really prefer your blog..! This blog are very useful for me and other. So I see it every day.
    Check out For Business ERP services at Naviworld.com.sg Cloud ERP Singapore. This cloud ERP software and system helps to reduce your startup costs by avoiding upfront hardware and software purchases Microsoft ERP solutions. NaviWorld Singapore is your go-to vendor.

    Visit Now - https://naviworld.com.sg/our-solutions/erp-cloud/
    Thanks.

    ReplyDelete