Azure function – Dynamics CE integration guide

Hi Folks,

In this blog post, we will talk about the integration of Dynamics CE first party apps(Model driven) with Azure.

You can integrate with Function Apps from Dynamics using two ways…

  1. Authenticate your Dynamics CE app within your Function app code
  2. Register a web hook to trigger a call to Azure functions using a trigger

We’ll see both the scenarios…

  1. Authenticate your Dynamics CE app within your Function app code

Open your favorite IDE and create azure function..in this case I’ll be using Visual studio.

Create a new Azure Function Project(Make sure you install the Azure functions project template using extensions).

Click on Next option at the bottom, in the next step specify your Function App name as below.

Don’t change other values and click on Create at the bottom of the page.

So in the next step, please make a note of the important things which were highlighted below..

Make sure you select the Target framework as .Net Framework.

You can select any trigger, but for simplicity I am selecting HTTP Trigger here.

In case you need to debug your Azure function and run it locally, then you need to be sure that you install Azurite Storage Emulator in your machine using this link, otherwise you can select None for the storage account option, if in that case make sure that your Azure function don’t need any storage.

Don’t change other values and click on Create at the bottom of the page.

This will take couple of mins to create the necessary scaffolding required for the Azure function.

Now you need to authenticate to your Dynamics Instance, so firstly right click on your project and select Manage Nuget Packages. Then you need to browse for Microsoft.Crm.Sdk.CoreAssemblies and install.

Then you will be able to authenticate your Azure function with Dynamics CE…once you were authenticated you can create a hard coded entity record in Dynamics whenever your function app runs.

The entire code…is hosted in GitHub for reference.

In this way you can an integration between Azure function and Dynamics 365

We will require the API testing tool, here I am using Postman and the following is the link to download “Postman”. https://www.postman.com/downloads/

To test the application, click on the Start button on top of Navbar as mentioned below in the screenshot [Button will have Project Name]. It will take a few minutes to Load the Azure Emulator

Run the Function App on the Local machine for testing.

Following is the screen you will be able to see and copy the URL highlighted in the red below and paste that URL in Postman.

Azure Function Tool

Open the Postman and click on the create a new tab

Postman Dashboard

Select request as POST and paste the URL:

After pasting the URL, click on Send

You will get the following response on the Azure Function Tool and Postman

The result after Sending Post Request to Azure Function

If there any error or issue with the Azure Function code, the request will be failed and will be displayed on both Azure Function Tool and Postman [Status will be “4**” or “5**” ]

Now, we will take look at Dynamics 365 CRM environment and check whether the account is created or not.

Result

Created customer from Azure Function.

2. Register a web hook to trigger a call to Azure functions using a trigger

Will update the post to add this logic next time.

Cheers,

PMDY

JavaScript Arrow Functions

In this tutorial, you will learn about JavaScript arrow function with the help of examples.

Arrow function is one of the features introduced in the ES6 version of JavaScript. It allows you to create functions in a cleaner way compared to regular functions. For example,

This function

// function expression
let x = function(x, y) {
   return x * y;
}

can be written as

// using arrow functions
let x = (x, y) => x * y;

using an arrow function.


Arrow Function Syntax

The syntax of the arrow function is:

let myFunction = (arg1, arg2, ...argN) => {
    statement(s)
}

Here,

  • myFunction is the name of the function
  • arg1, arg2, ...argN are the function arguments
  • statement(s) is the function body

If the body has single statement or expression, you can write arrow function as:

let myFunction = (arg1, arg2, ...argN) => expression

Example 1: Arrow Function with No Argument

If a function doesn’t take any argument, then you should use empty parentheses. For example,

let greet = () => console.log('Hello');
greet(); // Hello

Example 2: Arrow Function with One Argument

If a function has only one argument, you can omit the parentheses. For example,

let greet = x => console.log(x);
greet('Hello'); // Hello 

Example 3: Arrow Function as an Expression

You can also dynamically create a function and use it as an expression. For example,

let age = 5;

let welcome = (age < 18) ?
  () => console.log('Baby') :
  () => console.log('Adult');

welcome(); // Baby

Example 4: Multiline Arrow Functions

If a function body has multiple statements, you need to put them inside curly brackets {}. For example,

let sum = (a, b) => {
    let result = a + b;
    return result;
}

let result1 = sum(5,7);
console.log(result1); // 12

this with Arrow Function

Inside a regular function, this keyword refers to the function where it is called.

However, this is not associated with arrow functions. Arrow function does not have its own this. So whenever you call this, it refers to its parent scope. For example,

Inside a regular function

function Person() {
    this.name = 'Jack',
    this.age = 25,
    this.sayName = function () {

        // this is accessible
        console.log(this.age);

        function innerFunc() {

            // this refers to the global object
            console.log(this.age);
            console.log(this);
        }

        innerFunc();

    }
}

let x = new Person();
x.sayName();

Output

25
undefined
Window {}

Hope this helps in improvising your JavaScript code for your Power Platform Implementations

Happy CRM’ing.

Cheers,

PMDY

Fetch more than 5000 records in one go…paging cookie way…but there’s a catch….

Hi Folks,

Hope some day or the other, every CRM Consultant will face this issue where they need to retrieve more than 5000 records in one go.

As every one in the internet suggests, paging cookie is the easiest way to achieve the same.

However here there is a catch…if you will use distinct=”false” no-lock=”true” along with your fetch query, you will never achieve the expected result and the timeout error keeps on popping up.

Pretty surely Microsoft have had documented this one, but I couldn’t find any relevant Microsoft article stating this. So thought of sharing this tip over my blog so that some day it will help some one. Here is the complete solution…

//Call the method to use Paging cookie and fetch multiple records in one go....
EntityCollection fetchDonationTransactionRecords = RetrieveAll(service, fetch);

/// <summary>
        /// RetrieveAll
        /// </summary>
        /// <param name="service"></param>
        /// <param name="fetchXml"></param>
        /// <returns></returns>
        public static EntityCollection RetrieveAll(this IOrganizationService service, string fetchXml)
        {
            EntityCollection finalCollection = new EntityCollection();
            int fetchCount = 5000;
            // Initialize the page number.
            int pageNumber = 1;
            // Specify the current paging cookie. For retrieving the first page, 
            // pagingCookie should be null.
            string pagingCookie = null;

            while (true)
            {
                // Build fetchXml string with the placeholders.
                string xml = CreateXml(fetchXml, pagingCookie, pageNumber, fetchCount);
                EntityCollection recordsCollection = new EntityCollection();
                FetchExpression expression = new FetchExpression(xml);
                recordsCollection = service.RetrieveMultiple(expression);

                // * Build up results here *

                // Check for morerecords, if it returns 1.
                if (recordsCollection.MoreRecords)
                {
                    // Increment the page number to retrieve the next page.
                    pageNumber++;
                    pagingCookie = recordsCollection.PagingCookie;

                    foreach (var record in recordsCollection.Entities)
                    {
                        finalCollection.Entities.Add(record);
                    }
                }
                else
                {
                    // If no more records in the result nodes, exit the loop. 
                    if (finalCollection.Entities.Count >= 5000)
                    {
                        foreach (var record in recordsCollection.Entities)
                        {
                            finalCollection.Entities.Add(record);
                        }
                    }
                    else
                    {
                        finalCollection = recordsCollection;
                    }
                    break;
                }
            }
            return finalCollection;
        }

Hope this helps…that’s it for today…be safe & happy CRM’ing….

Cheers,

PMDY

Get selected options from Multiselect Option set

Mandar Joshi's avatarcrm backlog

{QuickPost}

Recently had a requirement to get all selected option texts from a multi select option set. Getting selected values is straight forward but I wanted to get the Label of selected values. For normal option set we can get it easily by using FormattedValues but that does not work with Multiselect Option set.

For C#:

Then found an handy code by Ravi Kashyap that was posted on community here. I have just restructured the function to make it generic.

Now just call the getSelectedOptionSetText() function and pass Organization Service, entity name and MultiSelect optionset field name.

The function first retrieves all the labels from the Option Set and then filters it with selected option set values.

public string getSelectedOptionSetText(IOrganizationService service, Entity enRecord, string fieldName)
{
string selectedText = string.Empty;
// Get the Formatted Values of MultiSelect OptionSet
List multiSelectTextCollection = GetOptionSetTextCollection(service, enRecord.LogicalName, fieldName);

if (enRecord.Contains(fieldName))
{
OptionSetValueCollection multiSelectValueCollection…

View original post 135 more words

Pro-grammatically create Document location records in SharePoint Online from Dynamics Customer Engagement Online without using native integration

Hi Folks,

Have you ever got a requirement to specifically create records in SharePoint without using the out of the box CRM-Sharepoint integration, then your were at right place and this post is going  absolutely help you with your requirement.

With the out of box integration, we will be able to create records in SharePoint when we navigate to OPEN LOCATION under Document Associated grid. But this adds record GUID to name of the record being created. But in our case, we only want the document location record to be created  with the name of the record. Please use the below code…all you need is Tenant ID, Resource ID, Client ID, Client Secret and your SharePoint domain and URL.

This approach uses Access token approach using the SharePoint based Add-in.

Steps to create SharePoint based Add-in. Navigate to below URL…

Ex: [Site Collection URL]/_layouts/15/AppRegNew.aspx0

AppRegNew Form

At this point, you’ll need to fill in the following details,

Name Description
Client Id Click Generate unique client id for your add-in. It’s a GUID which will be used to identify your add-in.
Client Secret Acts like a password for your add-in. It will include some special characters as well. So while using it, we have to encode the same first.
Title The name of your add-in that will be displayed to the end user.
App Domain For provider-hosted add-in, this will be the domain where, the add-in is hosted. For token generation add-in, fill in any value. Make sure, not to include protocols(https) or slashes(/).
Redirect URI For provider-hosted add-in, fill in the redirect URL. For token generation add-in, fill in any value.

Once you have filled in all the below details, hit Create to register the add-in1

Register SharePoint Add-in

    • You will be navigated to a page displaying the details of your add-in. Save Client Id & Client Secret for future references(Don’t forget this step as you won’t be able to navigate to this page to view details later)2                                  SharePoint Add-in Identifier
    • Grant permission to an add-in

      Now that the identifier is created, we need to grant the necessary permission for it to perform any action. In this example, I’ll demonstrate how to grant full control access on a Site Collection.

      • Navigate to
        [Site Collection URL]/_layouts/15/AppInv.aspx

        3

      • Enter your Client Id value in the App Id option and hit the Lookup button. Details of your add-in will be displayed automatically.4
      • Now this is crucial, you need to give permissions to your app. In the option, Permission Request XML, let’s write the below XML code to grant our add-in full control on the given site collection.Capture
      • Just hit the Create button. You will now be prompted to trust the add-in for all the permissions that it requires.5                                      Trust SharePoint Add-In
      • Hit the Trust It to grant the requested accesses. You can navigate to the following URL to also confirm that the permission has been assigned to the add-in.
        [Site Collection URL]/_layouts/15/appprincipals.aspx

        6

    • Now once you have created the app in SharePoint, you need to get the access token to perform CRUD Operations in SharePoint using REST API.
    • For testing purpose, you can use either POSTMAN or a console application…I have written the approach in both the ways.
    • For retrieving Tenant ID firstly using postman..
    • Perform a GET Request to the following URL..
    • [Site Collection URL]/_vti_bin/client.svc
    • After entering the above URL in the text-box in the URL text-box. We will get the Unauthorized exception on accessing the information. Because SharePoint Online is very much secured and that doesn’t allow anonymous users to access the information for their site. The below is the error message response, after sending the request. Highlighted is your Tenant ID..note it down..Capture1
    • Instead you can use the below C# code to get the Tenant ID details:public string GetTenant(string stGetTenantDetailsUrl)
      {
      WebRequest myWebRequest;
      string tenantID = string.Empty;
      string resourceID = string.Empty;
      string accessToken = string.Empty;myWebRequest = WebRequest.Create(stGetTenantDetailsUrl);
      myWebRequest.Method = “GET”;
      myWebRequest.Headers.Add(“Authorization”, “Bearer”);
      WebResponse myWebResponse = null; ;
      try
      {
      myWebResponse = myWebRequest.GetResponse();
      return tenantID;
      }
      catch (System.Net.WebException ex)
      {
      //get the Web exception and read the headersstring[] headerAuthenticateValue = ex.Response.Headers.GetValues(“WWW-Authenticate”);
      if (headerAuthenticateValue != null)
      {foreach (string stHeader in headerAuthenticateValue)
      {
      string[] stArrHeaders = stHeader.Split(‘,’);
      //loop all the key value pair of WWW-Authenticate
      foreach (string stValues in stArrHeaders)
      {if (stValues.StartsWith(“Bearer realm=”))
      {
      tenantID = stValues.Substring(14);
      tenantID = tenantID.Substring(0, tenantID.Length – 1);
      }
      if (stValues.StartsWith(“client_id=”))
      {
      //this value is consider as resourceid which is required for getting the access token
      resourceID = stValues.Substring(11);
      resourceID = resourceID.Substring(0, resourceID.Length – 1);
      }
      }}

      }

      return tenantID;//your tenant ID
      }
      }

    • Next step is to get the Access token..from Postman..

                                         Generate the Access Token

      In response header, we will get WWW-Authenticate as one of the header and that contains the necessary information required for next step. The realm value contains the tenant id for the SharePoint Online site and clientid value contains the resource information (we’ll use it later).

      Key Syntax Value
      Content-Type application/x-www-form-urlencoded application/x-www-form-urlencoded

      Body

      Key Syntax Value
      grant_type client_credentials client_credentials
      client_id ClientID@TenantID 4b4276d0-74cd-4476-b66f-e7e326e2cb93@10267809-adcb-42b6-b103-c7c8190b3fed
      client_secret ClientSecret nuC+ygmhpadH93TqJdte++C37SUchZVK4a5xT9XtVBU=
      resource resource/SiteDomain@TenantID 00000003-0000-0ff1-ce00-000000000000/spsnips.sharepoint.com@10267809-adcb-42b6-b103-c7c8190b3fed
      • After applying the configuration, click Send button. That will returns the response with the Access Token.

      Fig 7: Postman response contains Access Token

      You can use the below C# code to generate access token

      public string GetAuthorisationToken(string stGetAccessTokenUrl, string stSiteDomain, string tenantID, string resourceID, string stClientID, string stClientSecret)
      {

      string accessToken = string.Empty;
      stGetAccessTokenUrl = string.Format(stGetAccessTokenUrl, tenantID);

      WebRequest request = WebRequest.Create(stGetAccessTokenUrl);

      request.ContentType = “application/x-www-form-urlencoded”;
      request.Method = “POST”;

      string postData = “grant_type = client_credentials” +
      “&client_id =” + WebUtility.UrlEncode(stClientID + “@” + tenantID) +
      “&client_secret =” + WebUtility.UrlEncode(stClientSecret) +
      “&resource =” + WebUtility.UrlEncode(resourceID + “/” + stSiteDomain + “@” + tenantID);

      byte[] byteArray = Encoding.UTF8.GetBytes(postData);
      // Set the ContentType property of the WebRequest.
      request.ContentType = “application/x-www-form-urlencoded”;
      // Set the ContentLength property of the WebRequest.
      request.ContentLength = byteArray.Length;
      // Get the request stream.
      Stream dataStream = request.GetRequestStream();
      // Write the data to the request stream.
      dataStream.Write(byteArray, 0, byteArray.Length);
      // Close the Stream object.
      dataStream.Close();

      try
      {
      using (WebResponse response = request.GetResponse())
      {
      dataStream = response.GetResponseStream();
      // Open the stream using a StreamReader for easy access.
      StreamReader reader = new StreamReader(dataStream);
      // Read the content.
      string responseFromServer = reader.ReadToEnd();
      // Clean up the streams.
      reader.Close();
      dataStream.Close();
      //Get accesss token
      accessToken = “access_token\”:\””;
      int clientIndex = responseFromServer.IndexOf(accessToken, StringComparison.Ordinal);
      int accessTokenIndex = clientIndex + accessToken.Length;
      accessToken = responseFromServer.Substring(accessTokenIndex, (responseFromServer.Length – accessTokenIndex – 2));

      return accessToken;

      }
      }
      catch (WebException wex)
      {
      HttpWebResponse httpResponse = wex.Response as HttpWebResponse;
      createlog(_service, “Error occured” + wex.ToString());
      throw new InvalidPluginExecutionException(“Exception occured while retrieving Access Token” + wex.ToString());

      }

      }

      Once we are received the access token, you were all set and we got the authorization to access the SharePoint data based on the permission applied in Grant Permission of Add-In .

      So now we would implement our logic to create folders in plugin…make sure we should be passing the Access token received while accessing share point.

      public void CreateFolder(string sharePointSite, string token, string library, string folder,Guid entityID)
      {
      string result = string.Empty;
      StringBuilder sb = new StringBuilder();
      sb.Append(sharePointSite);
      sb.Append(“_api/web/GetFolderByServerRelativePath(decodedUrl='”);
      sb.Append(library);
      sb.Append(“‘)/Folders”);
      Uri uri = new Uri(sb.ToString().Replace(“{“, “”).Replace(“}”, “”));
      HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(uri);
      wreq.Headers.Add(“Authorization”, “Bearer ” + token);
      wreq.Method = “POST”;
      wreq.ContentType = “application/json”;
      string postData = “{‘ServerRelativeUrl’:’folder’}”;
      postData = postData.Replace(“folder”, folder);
      byte[] byteArray = Encoding.UTF8.GetBytes(postData);
      wreq.ContentLength = postData.Length;
      Stream dataStream = wreq.GetRequestStream();
      dataStream.Write(byteArray, 0, byteArray.Length);
      dataStream.Close();
      WebResponse wresp = null;
      try
      {
      wresp = wreq.GetResponse();
      using (wresp = wreq.GetResponse())
      {
      dataStream = wresp.GetResponseStream();
      StreamReader reader = new StreamReader(dataStream);
      string responseFromServer = reader.ReadToEnd();
      reader.Close();
      }
      }
      catch (WebException wex)
      {
      HttpWebResponse httpResponse = wex.Response as HttpWebResponse;
      createlog(_service, “Error occured” + wex.ToString());
      throw new InvalidPluginExecutionException(“Exception occured while creating record” + wex.ToString());
      }
      }

  • You can place the Client ID, Client Secret, Sharepoint domain name in Unsecure configuration in Plugin for easier movement of code to other environment.
  • Entire code is available here…you can grab it…
  • Hope this helps some one looking out integrating Dynamics CRM Online with SharePoint online without relying on out of box integration between Dynamics CRM & SharePoint.
  • Hope you enjoyed this post…please post your valuable comments..

Cheers,

PMDY