Auto Backup Dynamics 365 Solution using Flow & Dropbox

Harnessing the scaffold suggested in my last post, I would like to suggest a simple way to automatically backup Dynamics 365 solution with Flow/Logic Apps.

The following Flow will allow you to copy Dynamics 365 solution file into Dropbox account on schedule for backup or any other purpose.

You can download the scaffold Flow solution here and import into your Flow environment. Then, update the necessary details according to the following walkthrough. The last Dropbox related Action is not included, you’ll add it yourself.


Prerequisites

  1. Access to Microsoft Dynamics 365 online instance and Flow environment
  2. Register Microsoft Dynamics 365 online instance in Azure AD and have the Application Id key ready.Make sure you set the oauth2AllowImplicitFlow as described here.
  3. Have an accessible Dropbox account.

Walkthrough

Here is the full Flow collapsed Flow:

full Flow collapsed Flow

  1. Download the scaffold Flow solution here and import into your Flow environment
  2. Edit the imported Flow and set the following variables with values to match your environment:
    1. Client id & Dynamics 365 instance URL

      Client id & Dynamics 365 instance URL

    2. Set Dynamics 365 instance user name and password

      Set Dynamics 365 instance user name and password

    3. Set the target Dynamics 365 solution unique name and state the Dropbox target folder name (where the solution file will be created).
      Set false is the target solution is unmanaged, true otherwise

      Set the target Dynamics 365 solution unique name and Dropbox target folder where the solution file will be created.

    4. Add the Dropbox ‘Create File’ Action after the Parse JSON Action:
      Authenticate to your Dropbox account to allow creating the solution File in the target folder

      Authenticate to your Dropbox account to allow creating the solution File in the target folder

Once the Flow is activated, the target solution file will be created on schedule in the target Dropbox folder

Once the Flow is activated, the target solution file will be created on schedule in the target folder

Advertisement

Execute a Recurring Job in Microsoft Dynamics 365 with Flow

I have written about executing recurring jobs in Dynamics 365 few times in the past. Over time, I suggested different scheduling mechanisms such as Microsoft Dynamics Workflow Timeout step or Azure Scheduler, as the pattern I suggested allows changing the scheduling mechanism without impacting other solution parts.

Asynchronous Batch Process Pattern

Flow can be also used as a scheduling mechanism, one that does not require coding like Azure Function,  as it has a built in integration with Microsoft Dynamics 365 Online.
Once invoked on schedule, the executing component query Dynamics 365 for target business records and apply some business logic (Process) to each business record.

In this post I would like to demonstrate a solution for executing a recurring job in Microsoft Dynamics 365 using Flow as the scheduling component.

Sample business requirement

Weekly Leads Evaluation: once a week, disqualify all Leads that are more than 5 days old and are not rated ‘Hot’.
Add a note to each Lead record to indicate that it was disqualified by an automated process.

Walkthrough

  1. Download, Import and publish the ABP unmanaged solution.
  2. Create the Action component: Disqualify Lead Workflow

    This Workflow Rule will be applied to each valid target business record. It simply attaches a Note and changes the Lead record state to Disqualified. It can be a/synchronous, but you may want to start with a asynchronous execution to monitor the process execution.
    Make sure you define the process as an on-demand process with no automated triggers.

    Create the Action component: Disqualify Lead Workflow

  3. Define Target Business Records Query

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

    Define Target Business Records Query

  4. Create a Batch Process Record

    This record is used to orchestrate by holding a FetchXML query to define the target business records and also the Action process which will be applied on the the target business records.
    If you imported an unmanaged solution, find the Batch Process entity and set it to appear in the Settings area.
    Create a Batch Process record and paste the FetchXML query text into the Target Records textbox.
    Name the record ‘Weekly Leads Evaluation Process’.
    Select the Disqualify Lead Workflow (created in step 2) in the Process Lookup field and save the record.
    Copy the Reference Token value for the next step.

    Create a Batch Process Record

  5. Define Flow Rule

    In your tenant, navigate to the Flow area and create an empty Flow named Weekly Leads Evaluation.
    Define a Recurrence Trigger to trigger the batch process

    Define a Recurrence Trigger to trigger the batch processDefine a Recurrence Trigger to trigger the batch process

    Next, define a List records action.
    In the Filter Query text box, paste the Batch Process Reference Token value and precede it with dyn_referencetoken eq (e.g. dyn_referencetoken eq ‘LOGY8Y1W6’).

    Next, define a List records action

    Define Update record action which will automatically wrap it with Apply to each wrapper. Add a Condition before the Update Action to verify that the Flow operates only if the Batch Process record status is Scheduled. 

    Define Update record action which will automatically wrap it with Apply to each wrapper

  6. Activate

    Change the Batch Process record status to Scheduled and save.
    Activate the Flow Rule.
    You can monitor the Flow activation by navigating to the Run History area.

    You can monitor the Flow activation by navigating to the Run History area

    For each run, you can see the completion status (success/failure) and failure reason

    For each run, you can see completion status (success/failure) and failure reason

Similarly, you can now add additional scheduled batch processes. 

Implementation Details

Custom Code Tracing & Exception Logging in Dynamics 365 v.9

As a Solution Architect I often review Microsoft Dynamics 365 custom server and client side code.
One of the most common rejects regards tracing and exception handling mechanisms, or their absence. Some code constructs may have empty Try/Catch blocks or none at all, other catch exceptions and just re-throw. As for tracing, code often contains debugging ‘aids’ such as alerts and debugger statements or no tracing notifications at all.

Why is this a reject?

  • Unhandled raw exceptions float to UI, confusing and frustrating users while exposing internal implementation details to potential attackers
  • System Administrator is unaware of custom code exceptions unless users decide to report an error message or a bug
  • Tracing mechanism help diagnose faults and sometimes allow resolving without debugging or recompiling code

Microsoft Dynamics 365 contains a Plug-in Trace repository which contains trace and exception entries originating from Plug-in and Custom Workflow Activity components.
While this is a good built in solution, it has some drawbacks:

  • It does not support common types of custom code such as client side JavaScript and external components consuming Microsoft Dynamics API directly
  • There is no straight forward method to filter Plug-in Trace notification to search for specific text in trace/exception messages
  • No option to trigger a notification to system administrator once an exception is logged
  • No option to accurately correlate a user reported error message to a specific exception entry

In this post I would like to suggest an updated implementation of a more wholesome infrastructure for tracing and exceptions logging. Using this  infrastructure, any developer can easily log trace entries and exceptions from any custom code interacting with Microsoft Dynamics 365 application, while admins can easily monitor the application health in that aspect.

WIIFM

Why using this infrastructure?

  • Easily log trace entries and exceptions from any client and server side custom code interacting with Microsoft Dynamics 365 application in a unified manner
  • You can add processes triggered by exception Log record creation to alert system administrator regarding a fault as it occurs
  • Easily search and filter specific exceptions/trace records according to unique Reference Token provided by users/clients using Quick/Advanced Find

In the following How To Use section you can download a un/managed solution and follow setup and usage instructions.  You can view the GitHub project here.

How to use

  1. Download and import solution

    You can download a managed solution here.
    If you want to make any changes to this solution, download the un-managed version. In that case, open the solution, navigate to the Log entity and check ‘Settings’ to display the entity in the settings area. Finally, publish the solution.

    open the solution, navigate to the Log entity and check ‘Settings’ to display the entity in the settings area

  2. Using in an entity form JavaScript code

    Add the dyn_utils.js Web Resource to the target entity form libraries collection.
    Call the LogTrace and LogException functions in your custom code.

    Add the dyn_utils.js Web Resource to the target entity form Libraries collection

        //perform some business logic including tracing and exception handling 
        ns.DoSomeBusinessLogic = function () {
            //define verbose trace entry
            var traceEntry = {
                //title
                "title": "loggingSample.DoSomeBusinessLogic",
                //description
                "description": "Start execution",
                //related business record id 
                "relatedBusinessRecordId": "2514FC63-9E58-4D1E-8226-69256D0197E3",
                //related business record URL
                "relatedBusinessRecordURL": "https://xxx.crm.dynamics.com/main.aspx?etc=8&extraqs=&histKey=520872127&id=%7b2514FC63-9E58-4D1E-8226-69256D0197E3%7d&newWindow=true&pagetype=entityrecord#923042",
                //set current user id as related user id 
                "relatedUserId": getContext().userSettings.userId
            };
    
            //trace function execution start asynchronously
            Utils.LogTrace(traceEntry, true, SuccessHandler, FailureHandler);
    
            try {
                //some business logic including some exception 
                NonExistingFunctionCall();
            }
            catch (err) {
                //define verbose exception entry
                var exceptionEntry = {
                    //title
                    "title": "loggingSample.DoSomeBusinessLogic",
                    //description
                    "description": Constants.MSG_GENERAL_FAILURE,
                    //related business record id 
                    "errorMessage": err.message,
                    //related business record URL
                    "stackTrace": err.stack
                };
    
                //log exception and return reference token
                var referenceToken = Utils.LogException(exceptionEntry, false);
    
                //notify user with a reference token to report back to admin
                alert(Constants.MSG_GENERAL_FAILURE + referenceToken);
            }
            finally {
                //define thin trace entry 
                var traceEntry = {
                    //title
                    "title": "loggingSample.DoSomeBusinessLogic",
                    //description
                    "description": "Start execution",
                };
    
                //trace function exectuion end asynchronously
                Utils.LogTrace(traceEntry, true, SuccessHandler, FailureHandler);    
            }
        }
    
  3. Using in Web Resource JavaScript code

    You can view the code in action by launching the dyn_loggingSample.htm Web Resource (replace organization base address)
    https://YOUR_ORG_NAME.crm.dynamics.com//WebResources/dyn_loggingSample.htm

    You can view the code in action by launching the dyn_loggingSample.htm Web

    Make sure you include the dyn_utils.js as a referenced resource:

    
    
        
        Logging Sample
        
        
        
        
    
    

    The sample code in the dyn_loggingSample.js demonstrates tracing and exception handling, same as in the code sample above.

  4. Using in Plug-in/Custom Workflow Activity/external SDK client

    The following code sample represents usage in Plug-in and is similar to CWA and external SDK client usage:

        public class LogTraceAndException : IPlugin
        {
            public void Execute(IServiceProvider serviceProvider)
            {
                // Obtain the execution context from the service provider
                IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
                // Get a reference to the organization service
                IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService organizationService = factory.CreateOrganizationService(context.UserId);
    
                //define a trace entry, all attributes are optional except title 
                Log traceEntry1 = new Log
                {
                    title = "ServerSideLogging: Execute",
                    description = "Execution end",
                    //replace user id with an valid one
                    relatedUser = new EntityReference("systemuser", 
                        Guid.Parse("37ACCC73-0FCE-474B-A206-19C08163438B")),
                    relatedBusinessRecordURL = "https://YOURORGNAME.crm.dynamics.com/main.aspx?etc=1&extraqs=&histKey=87055256&id=%7b381FA757-60D7-E811-A97E-000D3AB20035%7d",
                };
    
                //log trace entry, get reference token back 
                string refToken1 = GenericLogging.Log(traceEntry1, 
                    GenericLogging.LogType.Trace, organizationService);
    
                try
                {
                    //some exception raising code.
                    //If transaction is rolled back, Log entries will persist
                    throw new Exception("An error occurred, please notify the System Administrator");
                }
                catch (Exception ex)
                {
                    //define an exception entry 
                    Log excptionEntry = new Log
                    {
                        title = "ServerSideLogging: Execute",
                        errorMessage = ex.Message,
                        stackTrace = ex.StackTrace
                    };
    
                    //log exception entry, get reference token back
                    string refToken2 = GenericLogging.Log(excptionEntry,
                        GenericLogging.LogType.Exception,
                        organizationService);
    
                    throw new InvalidPluginExecutionException(
                        string.Format("An error occurred, please notify the System Administrator. Reference token: {0}", 
                        refToken2));
                }
            }
        }
    

    A resulting exception raised from the Plug-in code includes the reference token. Once reported to an Admin, he can easily find the relevant Log entry using Quick Find

    A resulting exception includes the reference token

    Once reported to an Admin, he can easily find the relevant Log entry using Quick Find

    View Log details

Implementation Notes

I have written about the subject in the past and the described approach has not changed much. The implementation has been updated to leverage version 9 features (currently available on for Online implementations)

What has changed since last version:

  • Using Action definition to activate, deactivate and control logging level
  • Using built-in auto-numbering attribute to generate reference token, so a designated CWA component is no longer required
  • Optional usage of client side asynchronous logging operation to keep UX uninterrupted

In order to support logging from transactional components (such as Plugin registered to pre/post operation stages), the Log method in GenericLogging.cs file is using the ExecuteMultipleRequest class to execute the dyn_Log request.
As the ExecuteMultipleRequest instance is external to the Plugin transaction, it manages to create a Log record without the Plugin transaction rolling it back.
Using the Execute method directly with the dyn_LogRequest request instead, would have executed the Log Action, but the created Exception record would have been deleted by the Plugin transaction rollback, leaving no trace.

Custom Trace & Exception Logging diagram

 

Drag & Drop File Upload Revisited

Finally found the time for overdue maintenance on the Drag & Drop solution I created two years ago.

Why revisit?

First of all, as the CodePlex platform, previous home of this solution, is being decommissioned, downloading the component got the whole CodePlex project and few visitors commented that they could not find the actual solution.
So now you can download an unmanaged solution from it’s  new home @ Github.

Second, I fixed a major bug related to the plural name of some entities.
For most entities, appending ‘s’ to the entity schema name would result in the matching entity name for Web API. Some entities, like opportunity, do not match this pattern.

Third, I wanted to update the Web API version to 9.0 and to make sure the solution works with Dynamics 365 Online current version.

Drag and Drop demo

Non-interactive Access Mode

Why would you want to set Access Mode for user to Non-interactive? 

Setting the Non-interactive access mode fro a user will prevent him from accessing Dynamics 365 application UI in any official Dynamics 365 client: Web, Outlook and mobile. While human users need an GUI to actually do some work, external applications interacting with Dynamics 365 do not. Note that security mechanism such as Security Roles, Field Level Security etc. apply to users with Non-interactive access mode just as Read-Write users.

Assigning the Non-interactive access mode to applicative users used for interaction with external applications is a good security best practice as long as you assign the most restrictive Security Roles rather than System Administrator. This way, if this user’s credentials are breached, a potential attacker can access via API only, limited to the data scope and operations dictated by the Security Roles to begin with. 

If you do use the Non-interactive access mode for applicative user, consider the password renewal policy for this user, as there is not human on the the other side to actually change the password. This means that dependent integration points may fail due to expired password.

For more details about setting up a Non-interactive user follow this article.

image

Drag & Drop File Upload (part 1)

I have been planning to do this for over a year now, finally found the time. Started learning HTML5 (I recommend Pluralsight courses), and this is my first project.

In version 2016, Microsoft finally introduced some drag & drop file upload for the Word/Excel template feature, but that’s it. I would like to have similar UX in entity forms and Dashboards.

In this two-parts post, I’ll describe a working solution that allows users to upload a file by dragging it to a specific area in any business entity form or Dashboard.
The solution version available in this post adds an uploaded file as an attachment to a new Note record related to the context business entity. The next post version will use a more modular approach that can be used if you manage files outside of Microsoft Dynamics CRM database.


WIIFM?

An unmanaged solution can be downloaded here. Feel free to change the code to better suit you needs.

As this solution relies on HTML5 features, it will probably not work with early browsers versions. I tested it successfully with IE 11, Edge and Google Chrome v54.0.2840.71.
The solution uses the Web API service and therefore suitable for Microsoft Dynamics CRM 2016 Online and on-premise. For earlier MSCRM versions, some changes are required (read the Bits & Bytes section below)

Drag and Drop demo

Using the Solution

  1. Download, import and publish the Drag & Drop File Upload solution
  2. Add a Web Resource control to any business entity form
  3. In the Web Resource form, make sure the “Pass record object-type code…” option is checked
  4. Set the Web Resource format to span over 13 rows at least
  5. Map the Web Resource control to the dyn_DnDFileUploadArea.htm Web Resource
  6. Save & publish
  7. Drag n Drop like crazy

    image

Bits & Bytes

  • The solution code portion is contained in the dyn_DnDServices.js Web Resource
  • As the code uses Web API to create a Note record, it will not work with versions earlier than 2016. You can adapt the solution to earlier MSCRM versions by changing the createRecord function in the dyn_DnDServices.js Web Resource to use the OrgannizationData Service (REST) or the Organization Service (SOAP) to create a Note (Annotation) record
  • The code prevents uploading some file types (exe, js, etc.) according to the default blocked file extensions defined in the System Settings area. Maximum uploaded file size is also limited. Both settings are managed as constants and can be easily changed

    Managing blocked files extentions and file size settings   

  • I considered retrieving the blocked file extensions from the server instead of managing as constant. I opted for constants as I rather have better performance all year round over minor maintenance effort required once a year or maybe never 
  • You can can position the dyn_DnDFileUploadArea.htm Web Resource in a Dashboard. It will create Note record along with file attachment but will not relate it to any business record
  • Unfortunately, there is no supported manner to refresh the native Notes control. It would have been useful to automatically display the latest note after uploading a file

MSCRM 2016 Admin Utility – Personal Views Manager

You may have noticed that even under the almighty System Administrator Security Role, you can’t view (nor edit, share, assign or delete) other users Personal Views. Well, that’s what personal means. Via the application UI, only the view owner can manage it.

This restriction can be troubling in some scenarios:

  • A user who shared his Personal Views with other users or teams has left the organization and now no one can edit or delete these views which are irrelevant or just annoying
  • A user has defined and shared a resources hungry Personal View which execution make the application grind to a halt

In this post, I’ll demonstrate a utility which allows you manage other users Personal Views, as long as you have the right privilege.

WIIFM? 

As you can see below, after selecting a user, you can view and manage the user owned Personal Views by deleting or assigning to yourself:

Personal Views Manager demo

If you are not into JavaScript coding and just want to use this utility, you can download the unmanaged solution. After importing this solution, open it, navigate to the Configuration element and manage away. It is recommended that you have the System Administrator Security Role. 

Note
that this utility was developed and exported from Microsoft Dynamics CRM Online Organization (v2016) but it should work perfectly in an on-premise v2016 deployment.
If you are using an earlier version (2015 and below), this solution is not for you, as it uses v2016 new API. There are similar solutions available for earlier versions.

Curious about the implementation details? read on. 

Bits & Bytes

Major implementation notes:

  • Although this utility can be easily implemented on the server side, I opted for client side & Web API which requires less code lines to write and is easier to maintain
  • I intended to add an option to Share Personal Views but encountered Web API limitation, as the GrantAccess message is yet unsupported. One option to implement this feature is calling a Custom Action wrapping a Custom Workflow Activity to execute GrantAccess request
  • The entity used to represent a Personal View is userquery 
  • The magic feature enabling access to userquery records owned by other users is Web API impersonation
  • In order to use impersonation with MSCRM (client or server side), the executing user (consuming the Web Resource) must have the prvActOnBehalfOfAnotherUser privilege, which is granted by default by the built-in Delegate and System Administrator Security Roles:

    prvActOnBehalfOfAnotherUser privilege 

  • To execute code using impersonation, the MSCRMCallerID header must be added to XMLHTTPRequest along with the impersonated user id:

    using the MSCRMCallerID header

  • Some good news though: in order to Assign a record using Web API, you only have to update the onwerid attribute. Sound so trivial…why did we ever need AssignRequest?

    use update instead of AssignRequest

Editing Multiple Activities in Advanced Find Results Grid

One of my customers asked me why can’t she edit multiple Tasks (bulk edit) in Advanced Find results grid, while it is certainly possible in any other Tasks grid.

I was not aware of the this limitation and tested it myself. It seems that the Edit command is disabled for all Activity types in Advanced Find results grid when trying bulk edit.

Advanced Find Results Grid - bulk edit disabled

What is the purpose of this limitation? Don’t really know, but here a quick workaround:

Instead of searching for Tasks (or any other type of Activity), select Activities as the Advanced Find query entity and add a condition on the Activity Type column to match the required type.

Advanced Find query

For some reason, bulk edit is enabled for this query results.

Advanced Find Results Grid - bulk edit enabled

The downside of this workaround is that this query is limited to the general Activity attributes. If you need to query a custom Task attribute, you can save the query as a personal view, access it in any Tasks grid and bulk edit away.

Microsoft Dynamics CRM On Edge

I don’t usually blog about these topics, but I feel Windows 10 and the Edge browser justify it. Also, I need a little break from the ABP related posts.

Just upgraded my old laptop from Windows 7 to Windows 10 Enterprise. In the past, I have decided to skip Windows 8 altogether because it  made me feel like a fish out of the water and an unproductive one at it.

Windows 10 feels right to me.
It upgraded smoothly in about 1 hour and It runs great on my weak (3GB RAM, 2.4GHz dual core) laptop. The UX is very friendly and I know where to find everything.
Although I have only skimmed Windows 10, I feel I won’t regret upgrading.

The new Edge browser looks good. Clean and functional UI with good performance. Haven’t compared properly yet, but it feels at least as fast as Chrome, and like Chrome it uses multiple processes.

The best news, is that Microsoft Dynamics CRM (Online, RU 0.1) is running smoothly on Edge. No error messages, good performance (especially compared with IE).
This shouldn’t be taken for granted. As far as I can remember, no new version of IE could run Microsoft Dynamics CRM application from day one, without some adjustments made in IE browser, Microsoft Dynamics CRM application or both.

So in the next few days, I will be wearing Microsoft Dynamics CRM on Edge. I am looking forward to make Edge my default browser.

Microsoft Dynamics CRM 2015 on Edge browser