Implementing Dynamics 365 Service Bus Listener using Azure Function

One of the built-in triggers for Azure Function App is Service Bus (ASB) queue trigger, which makes Azure Function a listener for ASB events.
While Azure Service Bus provides a robust decoupling mechanism, the receiving side has to poll for messages or implement a listener

This trigger makes Azure Functions an ideal implementation component for Inbound Asynchronous Integration with Microsoft Dynamics 365,
one that allows you to write custom code, but releases you from explicitly writing a listener.
An Inbound Asynchronous Integration pattern describes scenarios where a business event occurs in an external application and must be reflected into Dynamics 365.
Processing of the event in Dynamics 365 does not occur immediately and sometimes no response is required from Dynamics 365 side (one way).

In this post I’ll walkthrough the process of setting an Azure Function as an ASB one-way listener which posts incoming messages into Dynamics 365.
To demonstrate posting a message to ASB I’ll use Postman.

Business Scenario:

Whenever a new Account record is created in Contoso’s ERP application, reflect the new Account data into Dynamics 365 CE.

Prerequisites:

  1. Azure subscription allowing you to register apps, provision Azure Service Bus and Azure Function App
  2. Microsoft Dynamics 365 9.x instance with admin privileges, a trial will do

Walkthrough:

  1. Setup Azure Service Bus queue and make a note of the connection string
  2. Register an AAD App and application user to allow using Microsoft Dynamics 365 Web API. Note the Application Id  and secret
  3. Setup Azure Function App with Service Bus queue trigger
     
    1. In Azure Portal, click ‘Create a resource’
      undefined
    2. Select Function App
      undefined
    3. Search for Function App (classic) and create a new one
      undefined

      undefined
    4. Set Function details and click ‘Create’
      undefined
    5. Select the new Function and click Function app settings
      undefined
    6. Select 1 as Runtime version
      undefined
    7. Select the Functions and Click New function
      undefined
    8. Select Azure Service Bus Queue trigger with C#
      undefined
    9. Set triggers details. Under Service Bus connection click new and select details for the ASB queue you set on stage 1

      undefined
      undefined
    10. Once back in the Function code, replace existing code with the code found here.
      This code parse the incoming message, authenticates to Dynamics 365 and create a new Account record.
      Replace the ApplicationId, Secret and WebAPIURL to match the details you noted on step 2 and your organization Web API URL.
      Save the Function and make sure it compiles.

      undefined
  4. Test by posting a message with the required format to ASB queue.
    You can post messages to ASB using Postman and this useful collection
    undefined
    Make sure Azure Function processes the message
    undefined
    and that the record was created in Dynamics 365
    undefined

Integrating Dynamics 365 with Azure Function using Managed Identity

I love Azure Functions. These days, I have to restrain the tendency to solve every problem with this Swiss army knife. 

When designing Azure Function integration with Dynamics 365, one of the immediate questions raised is where to store connection strings, credentials and other sensitive details. 
The immediate answer is ‘Not in your code’. So where?

One option is to store sensitive details in the Application Settings store which is ‘encrypted at rest and transmitted over an encrypted channel.’
While this option is  quite easy to use, it isn’t considered most secured.

One option is to store sensitive details in the Application Settings store

Another option is using Managed Identity with Azure Key Vault service.
With this option, Azure Function App is assigned an AAD identity, which is then authorized to access specific Key Vault secrets.
This option is considered more secured as the Function App is specifically granted access to  specific sensitive data, while Application Settings stored data is generally exposed.

In this post, I’ll walkthrough the process of setting and using Managed Identity to Integrate Azure Function with Dynamics 365. In this case, Dynamics 365 access details will be stored in Azure Key Vault.

For the walkthrough, I’ll use the Lead Landing Page scenario, replacing Flow component with Azure Function. Although a bit verbose, the process is quite simple.

Implementation Notes

  • Like most Azure services, Azure Key Vault usage costs money. With Azure Key Vault, any retrieval of secret is paid for. In order to reduce costs, some caching mechanism (which will not be discussed in this post) is in order.

Prerequisites

  1. Have accessible Microsoft Dynamics 365 instance
  2. Have access to Azure environment with sufficient privileges to create Azure Function and Key Vault store.

Walkthrough

  1. Register App with AAD

    Register a new Web App/API in Azure AD with a Client Secret and copy Application Id key and secret to Notepad.

  2. Add an App User to Dynamics 365

    Follow this article: Add a new Application User in Dynamics 365

  3. Create a Function App

    Create a Function App

    Set Function App details and click ‘Create’

    Set Function App details and click ‘Create’

    Add a new Function

    Add a new Function

    Select the HTTP trigger option

    Select the HTTP trigger option

    Click ‘Create’ to complete Function creation

    Click ‘Create’ to complete Function creation

    Leave the function code as is for now, we will alter it later on.

    Leave the function code as is for now, we will alter it later on.

  4. Assign Function App with a Managed Identity

    Go to the Function App Platform Features tab and click ‘Identity’

    Go to the Function App Platform Features tab and click ‘Identity’

    Click the ‘On’ button to assign a System identity and click ‘Save’

    Click the ‘On’ button to assign a System identity and click ‘Save’

    Click ‘Yes’ to enable system assigned managed indentity

    Click ‘Yes’ to enable system assigned managed indentity

    You can see the newly assigned identity object ID

    You can see the newly assigned identity object ID

  5. Setup Azure Key Vault store

    Create a new Azure Key Vault store

    Create a new Azure Key Vault store

    Click ‘Create’ at the bottom of the screen

    Click ‘Create’ at the bottom of the screen

    Click ‘Add new’ under the Access policies blade.
    In the Add access policy, check Get and List in the Key Management Operations group.
    Under the Principal blade, find and select your Function App. Click ‘Select’.
    This will grant our Function identity access to the Key Vault secrets.

    Click ‘Add new’ under the Access policies blade. In the Add access policy, check Get and List in the Key Management Operations group.

    Next, select a Resource Group for the Key Vault store. Click ‘Create’ to complete Azure Key Vault store creation

    Next, select a Resource Group for the Key Vault store

  6. Store secrets in Azure Key Vault

    Find the newly created Azure Key Vault store or access it from the dashboard if possible.

    Find the newly created Azure Key Vault store or access it from the dashboard if possible.

    Access the Secrets area

    Access the Secrets area

    Click Secrets and ‘Generate/import’ to generate a new secret

    Click ‘Generate/import’ to generate a new secret

    Set secret Name (select a self explanatory name, since once created, you won’t be able to see the actual secret value in the area).
    Set the secret string in the Value field. Click ‘Create’.
    In this case, the secret I defined is Dynamics Web API URL, similar to https://<ORGNAME>.api.crm<DATACENTERCODE>.dynamics.com/api/data/v9.1/

    Set secret Name (select a meaningful name, as this will be used in our code). Set the secret string in the Value field

    In the same manner, add additional secrets to hold the applicationId and secret keys you copied after registering an app in AAD (step 1 in this walkthrough).

    In the same manner, add additional secrets to hold the applicationId and secret keys you copied after registering an app in AAD

    Click each of the newly created secrets and copy the Secret Identifier, which will be used in the code to access the secret value

    Click each of the newly created secrets and copy the Secret Identifier, which will be used in the code to access the secret value

  7. Update Azure Function Code 

    Go back to the Function created on step 3 above.
    Click View Files, add a new project.json file and paste in the following definition. Click ‘Save’.

    {
        “frameworks”: {
            “net46”: {
                “dependencies”: {
                    “Microsoft.Azure.KeyVault”: “2.4.0-preview”,
                    “Microsoft.Azure.Services.AppAuthentication”: “1.1.0-preview”                
                }
            }
        }
    }

    image

    Go back to the function code and replace the existing code with the code found here (placed in Github for convenience).

    This code, triggered by an HTTP request from the Lead landing page, performs the following tasks:
    – Receives and parse Lead data
    – Extract Dynamics access details from Azure Key Vault
    – Use access details to generate an access token
    – Create a new Dynamics Lead record using Web API
    – Returns operation result to the caller

    In the GetDyn365AccessDetails method, replace the URLs for the three keys

    dyn365WebAPIURL, dyn365AppIdKVURL, dyn365secretKVURL with the URLs copied on step 6.
    Click ‘Save’.

    Click ‘Get Function URL’ and paste somewhere, as it will be used next

    Click ‘Get Function URL’ and paste somewhere, as it will be used next

  8. Hookup Lead Landing Page to Azure Function

    Last, create a new HTML page, and copy the HTML found here (placed in Github for convenience).
    Find the AzureFunctionRequestURL variable and replace its value with the Azure Function URL copied in the previous step. Save.

    Find the AzureFunctionRequestURL variable and replace its value with the Azure Function URL copied in the previous step

  9. Test

    To test the solution, run the Lead Landing HTML page. Submitting Lead data should results with a new Lead record in Dynamics 365.

    To test the whole flow, run the Lead Landing HTML page

    Submitting Lead data should results with a new Lead record in Dynamics 365.

    If the flow fails, add the address from which the HTML page is executed to the Azure Function CORS collection to authorize it.

    If the flow fails, add the address from which the HTML page is executed to the Azure Function CORS collection to authorize it.

    If the flow fails, add the address from which the HTML page is executed to the Azure Function CORS collection to authorize it.

Referencing Dynamics Assemblies with Azure Function Apps v.2

Just stumbled upon a new  Azure environment, where Azure Function Apps have been upgraded to version 2.
Right away, noticed that my Azure Function code referencing Dynamics assemblies does not compile, complaining about

The type or namespace name ‘Xrm’ does not exist in the namespace ‘Microsoft’ (are you missing an assembly reference?)

After digging around, I found out that the project.json is not longer valid with v.2.
Instead, the function.proj file must be created and reference Dynamics assemblies in the following manner:

<Project Sdk=”Microsoft.NET.Sdk”>

  <PropertyGroup>

    <TargetFramework>461</TargetFramework>

  </PropertyGroup>

  <ItemGroup>

    <PackageReference Include=”Microsoft.CrmSdk.CoreAssemblies” Version=”9.0.0.7″/>

    <PackageReference Include=”Microsoft.CrmSdk.XrmTooling.CoreAssembly” Version=”9.0.0.7″/>

  </ItemGroup>

</Project>

Instead, the function.proj file must be created and reference Dynamics assemblies in the following manner