Execute a Recurring Job in Microsoft Dynamics 365 with Azure Scheduler

The requirement for recurring job execution is quite common in Microsoft Dynamics implementations. Here are some of the business requirements I have encountered:

  • Send monthly newsletter to target customers
  • Synchronize MSCRM Users details with Active Directory once a day
  • Once a month, disqualify all leads that have no open activities
  • Once every hour, export Appointments from mail server and import into Dynamics 365

Microsoft Dynamics 365 has no reliable built in scheduling mechanism that can be leveraged for custom solutions. The Asynchronous Batch Process Pattern I have written about in the past can be used with daily recurring jobs but when it comes to hours resolution and less, it becomes unsteady.

Azure Scheduler is a reliable service that can run jobs in or out of Azure on a predefined schedule, multiple times or just once. So why not harness this mechanism to schedule Microsoft Dynamics 365 recurring jobs?

In this post, I’ll demonstrate how to use Azure Scheduler to execute a recurring job in Microsoft Dynamics 365.

Sample business requirement

Each day, automatically email a birthday greeting to contacts whose birthday occurs on that same day.

Implementation Details

Here are the solution main components:

  1. Custom Action dyn_SendBirthdayGreetings: activates a Custom Workflow Activity SendBirthdayGreeting which Retrieve all relevant Contact records by birthdate, creates and sends an email for each contact record.
  2. Azure Function BirthdayGreetingsFunction: invokes the dyn_SendBirthdayGreetings Custom Action via Microsoft Dynamics 365 API.
  3. Azure Scheduler BirthdayGreetingsSchduler: set to execute once a day at 9:00 for unlimited occurrences and invokes the BirthdayGreetingsFunction Azure Function

Architectural Notes

Why using Custom Action? Although it is possible to manage the required business logic in Azure Function, Dynamics related business logic should reside within Dynamics, managed and packaged in a Solution. This way, the Scheduling and Executing components are kept agnostic and isolated as possible and therefore easily maintained.
Having said that, you should be aware of the Sandbox Execution Timeout Limitation and consider using Custom Workflow Activity after assessing the business logic at hand.

Implementation Steps:

  1. Define dyn_SendBirthdayGreetings Custom Action

    Download, import and publish the unmanaged BirthdayGreetingAutomationSample_1_0_0_0 solution.
    It contains a Custom Action called dyn_sendBirthdayGreeting which will be later called from the BirthdayGreetingsFunction Azure Function.
    By default, the Custom Action will create a birthday greeting email but will not send it. To change this, disable the Custom Workflow Activity, edit the only step and change the Send greeting email after creation? property value to true. Note that this may actually send email to your contacts.
    The SendBirthdayGreeting Custom Workflow Activity code can be found here.

  2. Define BirthdayGreetingsFunction Azure Function

    After creating a Function App (follow the first 3 steps here), create a new C# Function of type Generic webhook under your Function App functions collection, name it SendBirthdayGreetingFunction

    Create a new Function of type Generic webhook under your Function App collection, name it SendBirthdayGreetingFunction

    name it SendBirthdayGreetingFunction
    Click the App Service Editor option in the Application Settings tab

    Click the App Service Editor option in the Application Settings tab

    Add a new file under your Function root, name it project.json. Copy the following JSON snippet into the text editor

    Add a new file under your Function root, name it project.json. Copy the following JSON snippet into the text editor

    {
    	"frameworks": 
    	{
    		"net46":
    		{
    			"dependencies": 
    			{
    				"Microsoft.CrmSdk.CoreAssemblies": "9.0.0.7",
    				"Microsoft.CrmSdk.XrmTooling.CoreAssembly": "9.0.0.7"
    			}
    		}
    	}
    }
    

    Close the App Service Editor to get back to your function. Selecting your Function App, click the Application settings tab.

    Close the App Service Editor to get back to your function. Selecting your Function App, click the Application settings tab

    Scroll down to the Connection strings area and add a new Connection string named TargetOrganization. This will be used to connect and authenticate to your Microsoft Dynamics 365 Organization.
    For the connection string value, set your organization details in the following format:

    AuthType=Office365;Username=XXX@ORGNAME.onmicrosoft.com;Password=PASSWORD;Url=https://ORGNAME.crm.dynamics.com

    Note the data center targeted, crm.dynamics.com is targeting an organization in North America data center.

    Click Save to save the newly created Connection String.

    Scroll down to the Connection strings area and add a new Connection string named TargetOrganization
    Navigate back to your SendBirthdayGreetingFunction function and  replace the default Function code with the following code snippet.
    Note that code is executing a Custom Action named dyn_SendBIrthdayGreetings.It also uses the TargetOrganization connection string when accessing Microsoft Dynamics 365 API.

    using System.Net;
    using System.Configuration;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Client;
    using Microsoft.Xrm.Tooling.Connector;
    
    public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
    {
        string actionResponse = string.Empty;
    
        //define Dynamics Custom target Action name 
        string actionName = "dyn_SendBirthdayGreetings";
    
        log.Info("Processing new SendBirthdayGreetingFunction request");
    
        //init Dynamics connection, authenticate and get referent to the Organization Service
        IOrganizationService organizationService = InitDynamicsConnection();
    
        //execute Custom Action  
        OrganizationRequest sendBirthdayGreetingsReq = new OrganizationRequest(actionName);
        OrganizationResponse sendBirthdayGreetingsRes = 
            (OrganizationResponse)organizationService.Execute(sendBirthdayGreetingsReq);
    
        //return completion status response 
        return actionResponse == null
            ? req.CreateResponse(HttpStatusCode.BadRequest, "An error occured")
            : req.CreateResponse(HttpStatusCode.OK, "Action completed successfully");
    }
    
    //init Dynamics connection
    private static IOrganizationService InitDynamicsConnection()
    {
        IOrganizationService result = null;
    
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
        CrmServiceClient client = new CrmServiceClient(
            ConfigurationManager.ConnectionStrings["TargetOrganization"].ConnectionString);
    
        result = client.OrganizationServiceProxy;
    
        return result;
    }
    

    Navigate to the Function Integrate area and set the Mode to standard. This will enable the consumption of the function using HTTP GET method.

    Navigate to the Function Integrate area and set the Mode to standard. This will enable the consumption of the function using HTTP GET method

    Back at your Function code editor, expand the collapsed Test pane and set the HTTP method to GET. Click Run to test your function. If all went well, a success message will be returned.

    Back at your Function code editor, open expand the collapsed Test pane and set the HTTP method to GET. Click Run to test your function. If all went well, a success message will be returned.

    Finally, click the </> Get function URL button on top and copy your function endpoint address.

  3. Define BirthdayGreetingSchduler Azure Scheduler

    Click the + New button on the left menu, type in Scheduler and select the Scheduler element returned. Click Create

    Click the + New button on the left menu, type in Scheduler and select the Scheduler element returned

    Define the scheduler name to BirthdayGreetingSchduler.

    Define the scheduler name to BirthdayGreetingSchduler

    Click the Action settings tile. Set the Action to Https, method to Get and paste in the Function URL you copied at the end of the step 2 above. Click OK

    Click the Action settings tile. Set the Action to Https, method to Get and paste in the Function URL you copied at the end of the step 2 above. Click OK

    Click the Schedule tile and set the schedule as Recurring, frequency to Days and End to Never. Click the Advanced schedule pane and set 9 in the Hours text box. Click Ok.
    This will trigger your function every day at 9:00 for unlimited number of times.
    Check Pin to dashboard and click Create.

    This will trigger your function every day at 9:00 for unlimited number of times.

    After a few seconds, you will be navigated to the Scheduler management area.

  4. Test

    To test the complete solution, update a Microsoft Dynamics 365 test Contact record birthdate to match the day and month of the current date.

    Go back to your Scheduler Job and click Run now.

    Go back to your Scheduler Job and click Run now.

    Clicking the History tab, you can monitor the Schedule job completion status

    Clicking the History tab, you can monitor the Schedule job completion status

    Refreshing the Sample Contact activities list, you should be able to view the newly created Birthday greeting email

    Refreshing the Sample Contact activities list, you should be able to view the newly created email

Advertisements

Web API: Executing Custom Action via JavaScript

The Custom Action is an important tool in Microsoft Dynamics CRM architect belt. Here are some of the Custom Action key features:

  1. It can be called from both client & server side, enabling the SPoI approach (Implement once, consume anywhere)
  2. Supply a flexible, declarative business logic definition mechanism which can be called from other Processes as well as from custom code (unlike Plug-in)
  3. Can be extended with Custom Workflow Activities
  4. Can receive input parameters and return output parameters in a straight forward manner, similar to an Organization level Web Service

Why would you want to execute a Custom Action (which is a server side mechanism) via JavaScript? Here are some excellent reasons:

  • Provide an improved UX, as Custom Action can be executed a-synchronously from entity forms, web resources and Ribbon/Command Bar controls without blocking the user UI
  • You can bind server side logic to client side events, e.g. calling a Custom Action from an onChange or onSave event handlers
  • Implement a chunky rather than chatty communication with the server, as Custom Action usually wraps multiple operations which otherwise require multiple API commands

You can execute a Custom Action via JavaScript using raw SOAP (not recommended) or better yet, using the Sdk.Soap.js library (still SOAP, but nicely wrapped).
With Microsoft Dynamics CRM 2016 Web API you can now execute a Custom Action in the most simple manner, which is demonstrated in the rest of this post.

You can download an unmanaged Solution containing the sample Action and JavaScript code. This solution is for demonstration purposes only, please do not install on production or other critical environments.

  1. Define and activate a Custom Action in MSCRM 2016 Organization

    My sample Action receives few parameters, creates a Lead record and returns the new record URL.
    Note that this Action is defined for a global context. Also note the Action’s unique name and parameters names which are used in the following code.

    Define Custom Action

  2. Write JavaScript code to consume your Action

    The handleWebLead function defines the dyn_HandleWebLead Action name and parameters.
    It than calls the generic activateCustomAction function to execute the Action and return the output result.

    Define calling function
     
    The Action is executed using XMLHttpRequest which is defined to execute synchronously.

    Define Action executing function

Asynchronous Batch Process Solution Revisited – part 4

In the previous post, I walked through the ABP (Asynchronous Batch Process) Aggregative Query Scenario. In this post, last in this series, I’ll go through the External Action scenario.

Prerequisites

1. Download the Asynchronous Batch Process Solution, import into Microsoft Dynamics CRM 2015 on-premise/Online organization
2. Go to Settings – > Solutions and Open the ABP solution. Go to the Batch Process entity definition and check the Settings checkbox in the ‘Areas that display this entity’ section
3. Save and publish the solution

As always, I advise against publishing any external solution on your production environment without testing it first.

External Action scenario

This scenario describes a scheduled action, not necessarily related to Microsoft Dynamics CRM records, hence external.
The target records FetchXML query can be used but it is optional.
This action is usually a wrapper for Custom Workflow Activity performing some magic which the native process tools can not.

Some sample business requirements of this type:

– Retrieve users data from AD (Active Directory) on daily basis and update Microsoft Dynamics CRM users data accordingly
– Import/export data to/from Microsoft Dynamics CRM to an external application over night
– Generate and email SSRS report to a mailing list every month

Following are the steps to implement the daily AD users data synchronization. For this scenario I assume you already registered a Custom Workflow Activity with some capability to retrieve data from AD and update System User records.

1. Create a new Action targeting ‘None (global)’ and name it ‘Synchronize AD users’
2. Add a step to activate the AD synchronization Custom Workflow Activity component
3. Save and activate the process

image

4. Create a new Batch Process record (Settings –> Batch Processes)
5. Name the Batch Process: ‘Daily AD users synchronization’ (or other meaningful name)
6. Set the Activation Frequency to ‘Daily’
7. Set the Process field value to ‘Synchronize AD users’ process
8. Set the Next Activation to any future date and time. I suggest selecting the application’s least busy time
9. Set the Status Reason to ‘Scheduled’
10. Click Save to schedule the Batch Process

image

You are done! The Batch Process is set and waiting for the next activation date and time. If all goes well, the AD users
synchronization will execute as defined and the Batch Process will reschedule to the same time next day.

If you would like to deactivate the Batch Process scheduling, change the Status Reason value to ‘Suspended’ and save. Since there may already be a Workflow instance scheduled and waiting, go to the Background Processes for the Batch Process record and cancel waiting instances.
This also applies if you change the Next Activation date/time once the Batch Process record is already created and scheduled.

I hope you find the scenarios I have described in the series as useful to you. If you have development skills or resources, you can customize the ABAP solution as you like, the source code is available on CodePlex.
I will keep adding features to this component and upgrade along with Microsoft Dynamics CRM versions until MS supplies a similar built in solution.

Asynchronous Batch Process Solution Revisited – part 3

In the previous post, I walked through the ABP Target Records Scenario. In this post, I’ll go through the Aggregative Query Scenario.

Prerequisites

1. Download the Asynchronous Batch Process Solution, import into Microsoft Dynamics CRM 2015 on-premise/Online organization
2. Go to Settings – > Solutions and Open the ABP solution. Go to the Batch Process entity definition and check the Settings checkbox in the ‘Areas that display this entity’ section
3. Save and publish the solution

As always, I advise against publishing any external solution on your production environment without testing it first.

Aggregative Query Scenario

This scenario describes a scheduled aggregative calculation on Microsoft Dynamics CRM records, followed by performing some business logic operation with the calculation result. Due to the aggregative calculation result nature, the business logic operation is usually an email notification or record creation/update.
Note that grouping is unsupported by this version of the ABP.

Some sample business requirements of this type:

– Send daily email message to Service Manager with total number of daily resolved cases
– Each month, create a Note for each Sales Person user, recording total estimated revenue of opened Opportunities
– Send monthly report to an external application with sum of total closed Orders

Unfortunately, it is not yet possible to define aggregative queries using the Advanced Find editor, but there are useful tools such as FetchXMLBuilder (part of the XRMToolBox  suite) that can help you define FetchXML syntax for such queries.
Also, the Microsoft Dynamics CRM SDK contains useful samples for aggregative queries which can be easily tweaked to suit your purpose.

Following are the steps to implement the daily resolved cases requirement:

1. Create a new Action targeting ‘None (global)’ and name it ‘Send daily resolved cases total notification’
2. Uncheck all ‘Start when’ trigger checkboxes to prevent automatic triggering of the process
3. Add an input parameter of type string named aggregationResult. This specific name is critical for for the ABP operation.
4. Add a step to send an email notification to the Service Manager, including the required text embedding the aggregationResult parameter value
5. Save and activate the process

Send daily resolved cases total notification process

daily resolved cases total notification email

6. Define aggregative query. I used the FetchXMLBuilder too available in the XRMToolBox  suite and copy the query text to the clipboard

Aggregative fetchXML query definition

7. Create a new Batch Process record (Settings –> Batch Processes)
8. Paste the aggregative FetchXML query into the Target Records field. Note that the alias is used as as part of the aggregation result, so a meaningful name is preferred
9. Name the Batch Process: ‘Daily resolved cases total notification’ (or other meaningful name)
10. Set the Activation Frequency to ‘Daily’
11. Set the Process field value to ‘Send daily resolved cases total notification’ process
12. Set the Next Activation to any future date and time. I suggest selecting the application’s least busy time
13. Set the Status Reason to ‘Scheduled’
14. Click Save to schedule the Batch Process

Batch process definition

You are done! The Batch Process is set and waiting for the next activation date and time. If all goes well, an email notification will be sent as defined and the Batch Process will reschedule to the same time next day.

Total cases resolved today email

If you would like to deactivate the Batch Process scheduling, change the Status Reason value to ‘Suspended’ and save. Since there may already be a Workflow instance scheduled and waiting, go to the Background Processes for the Batch Process record and cancel waiting instances.
This also applies if you change the Next Activation date/time once the Batch Process record is already created and scheduled.

In the next post, I’ll walkthrough the External Action scenario. Stay tuned.

Asynchronous Batch Process Solution Revisited – part 2

In my previous post, I described some of the Asynchronous Batch Process Solution (ABP) version 2 internals. In the next posts, I would like to go through different business scenarios and explain how to use the ABP solution, step by step.

Prerequisites

1. Download the Asynchronous Batch Process Solution, import into Microsoft Dynamics CRM 2015 on-premise/Online organization
2. Go to Settings – > Solutions and Open the ABP solution. Go to the Batch Process entity definition and check the Settings checkbox in the ‘Areas that display this entity’ section
3. Save and publish the solution

As always, I advise against publishing any external solution on your production environment without testing it first.

Target Records Query Scenario

This scenario describes a business logic operation (Action) which is automatically applied to a collection of Microsoft Dynamics CRM records (target records), either once or repeatedly.

Some sample business requirements of this type:

– Send birthday greeting to target Contacts on their birthday date
– Send monthly newsletter to target customers
– Weekly Leads Evaluation – once a week, disqualify all Leads that are more than 5 days old and are not rated ‘Hot’
– Update large collection of records by overriding the 250 records limit (max. grid page size)

Following are the steps to implement the Weekly Leads Evaluation requirement:

1. Create a new Process (Workflow Rule (real-time/background) or Action) targeting the Lead entity and name it ‘Inactive Lead Disqualify’
2. Uncheck all ‘Start when’ trigger checkboxes to prevent automatic triggering of the process
3. If you created a Workflow Rule, check the ‘As an on-demand process’ checkbox and select the correct Scope
4. Add a Check Condition step to test if the Lead record is in an Open status. Add another step to change Lead Status to Cancelled (Disqualified state)
5. Save and activate the process

Define Action Proces

6. Open Advanced Find and define a new query to retrieve all Lead records where Created On date is older than 5 days and are not rated ‘Hot’
7. Click to Edit Columns button and remove all columns to maximize the query efficiency
8. Click the Download Fetch XML button and open the resulting file with some text editor
9. Copy the FetchXML query text to the clipboard

Define Advanced Find query

10. Create a new Batch Process record (Settings –> Batch Processes)
11. Paste the FetchXML query test into the Target Records field
12. Name the Batch Process: Weekly Leads Evaluation Process (or other meaningful name)
13. Set the Activation Frequency to ‘Weekly’
14. Set the Next Activation to any future date and time. I suggest selecting the application’s least busy time
15. Set the Status Reason to ‘Scheduled’
16. Click Save to schedule the Batch Process.

You are done! The Batch Process is set and waiting for the next activation date and time.

Define Batch Process Record

Looking at the Background Processes tab for the Batch Process record, you should notice one waiting Workflow instance which is waiting to retrieve all matching Lead records and to apply the Inactive Lead Disqualify process to each resulting record.

Background processes view

Once the Batch Process was executed once, you will notice that the Next Activation date was rescheduled for one week after the last activation.
If all went right, the Last Activation Completion Status is Success and the Activation Counter is set to 1.

Rescheduled Batch Process record

 

 

If you created a background Workflow Rule, you can view a list of the records that were affected by the batch process execution. To do that, navigate to the Inactive Lead Disqualify workflow rule and click the Process Sessions tab.

Affected records view

If you would like to deactivate the Batch Process scheduling, change the Status Reason value to ‘Suspended’ and save. Since there may already be a Workflow instance scheduled and waiting, go to the Background Processes for the Batch Process record and cancel waiting instances.
This also applies if you change the Next Activation date/time once the Batch Process record is already created and scheduled.

In the next post, I’ll walkthrough the Aggregative Query Scenario.

Microsoft Dynamics CRM 2013 Custom Action – A Single Implementation Point

Microsoft Dynamics CRM 2013 introduced a new member in the Processes family: Custom Actions.
I see great potential in this new feature, especially as it can be easily executed (synchronously or a-synchronously) from client side code and return results. While Synchronous Workflow can also be executed from client side code, it can’t return results in an elegant manner.

This Custom Action capability enables both server side and client side to share a single implementation point. Here is an example:

Lets say that whenever a Contact record is created, the government id number must be validated (9 digits that adhere to a specific algorithm). Contacts are created manually by users but also programmatically as part of a scheduled integration with an external application.

User experience considerations dictate a client side validation, as we want to warn the user about an invalid value when he changes the field value rather than when when saving the record.
But what about the records created programmatically? We have to add another point of implementation in the form of a Plugin or a Synchronous Workflow to support that.
So we end up with two implementation points, both JavaScript code and a server side component code. This means more development and maintenance efforts.

Let’s review a different solution approach using Custom Action:

  1. Develop a ‘IDValidation’ Custom Workflow Activity to preform the required validation and return a Boolean (valid/invalid) result.
  2. Wrap the IDValidation’  Custom Workflow Activity with a Custom Action and call the Custom Action from JavaScript onchange event (see Andrii’s useful solution here).
  3. Call the Custom Action directly from your server side integration code or wrap the Custom Workflow Activity with a Synchronous Workflow to support records created programmatically

This approach uses a single custom code component consumed both from server and client side, therefor reducing development and maintenance efforts.

Sharing Business Records via Processes in Microsoft Dynamics CRM

Microsoft Dynamics CRM 2013 Added new Workflow based mechanisms: Custom Action and Real Time (synchronous) Workflow. Along with Dialogs and Background (a-synchronous) Workflow, these mechanisms render the already powerful Processes family into a versatile implementation suite which allows implementing complex business logic in online and on-premise deployments. Some business logic which in version 2011 was only achievable via custom code, can now be achieved via declarative Process.

This versatility increases the ROI on Custom Workflow Activities components development as these components, which complete the capabilities of the Processes family via code, can now be reused in even more business scenarios by non developers.

One functionality is painfully missing in the Processes basic toolbox: the Share functionality. This may derive from the potential negative performance impact related to record Sharing in large scales which must be taken into consideration when planning an implementation.
It is recommended to share records with Teams rather than with single Users, and also to revoke shared privileges when ever possible.

To supply the required Share functionality via Processes, a Custom Workflow Activity can be used. Custom Workflow Activity is a DLL developed in .NET and deployed to Microsoft Dynamics CRM organization. It allows extending the Process capabilities with custom functionality. Once developed and deployed, this component can be used in Dialogs, Workflows (a-synchronous and synchronous) and Custom Actions in various business scenarios for different entities.

In order to Share a business record with a User or Team, some input details are required. These details are mapped by the user defining the Process hence the Custom Workflow Activity component must support matching input parameters:

  • Target record – which business record is to be shared?
  • Target principal – with what User/Team is the target record to be shared?
  • Share privileges – what privileges (read/write/delete etc.) are to be granted to the Target Principal regarding the Target record?

There are some challenges in developing a generic Custom Workflow Activity component, which I will discuss next.

One major challenge is making this component generic enough to handle any entity that supports the Share operation.
This challenge derives from the Custom Workflow Activity input parameter types, which sadly do not include the Entity class. The supported EntityReference parameter type requires the ReferenceTarget attribute, which bind it to a specific entity type. So using EntityReference does not achieve the required generic solution.

My solution is to let the user (who defines the Process) define the target entity schema name as an input parameter of string type. This approach puts the responsibility of getting the entity schema name on the user defining the Process. I trust anyone who is can define a Process is capable of correctly copying the entity schema name from the entity customization page.

Another challenge is getting the id of the target business record. As this component is required to operate on any sharable entity, the user defining the process must be able to point to any business record of any entity. Again, the Custom Workflow Activity input parameter types limit us.

The solution here relies on the Workflow ability to supply the URL of any business entity as part of the attributes exposed in the Workflow editor. As this URL eventually contains the record GUID (unique record id), it can be used to supply the required target business record id.

The rest of the input parameters are more trivial. As records can be shared with either User or Team, two EntityReference input parameters allow specifying the target principal respectively. The privileges input parameter allows the user to specify the required privileges via a simple string.

The same approach can be implemented in version 2011 as well.

Untitled