Back only a few years ago, when events such as a reality TV star becoming President of the USA were the stuff of fantasy fiction, Microsoft had a somewhat niche Customer Relationship Management system called Dynamics CRM. Indeed, the very name of this blog still attests to this fact. The “CRM” acronym provides a succinct mechanism for describing the purposes of the system without necessarily confusing people straight out of the gate. For the majority of its lifespan, “CRM” very accurately summarised what the core system was about – namely, a sales and case management system to help manage customer relations.

Along the way, Microsoft acquired a number of organisations and products that offered functionality that, when bolted onto Dynamics CRM, greatly enhanced the application as a whole. I have discussed a number of these previously on the blog, so I don’t propose to retread old ground. However, some notable exceptions from this original list include:

Suffice to say, by the start of 2016, the range of functionality available within Dynamics CRM was growing each month and – perhaps more crucially – there was no clear mechanism in place from a billing perspective for each new solution offered. Instead, if you had a Dynamics CRM Professional license, guess what? All of the above and more was available to you at no additional cost.

Taking this and other factors into account, the announcement in mid-2016 of the transition towards Microsoft Dynamics 365 can be seen as a welcome recognition of the new state of play and the ushering in of Dynamics CRM out of the cold to stand proud amongst the other, major Microsoft product offerings. Here’s a link to the original announcement:

Insights from the Engineering Leaders behind Microsoft Dynamics 365 and Microsoft AppSource

The thinking behind the move was completely understandable. Dynamics CRM could no longer be accurately termed as such, as the core application was almost unrecognisable from its 2011 version. Since then, there has been a plethora of additional announcements and changes to how Dynamics 365 in the context of CRM is referred to in the wider offering. The road has been…rocky, to the say the least. Whilst this can be reasonably expected with such a seismic shift, it nevertheless does present some challenges when talking about the application to end users and customers. To emphasise this fact, let’s take a look at some of the “bumps” in the road and my thoughts on why this is still an ongoing concern.

Dynamics 365 for Enterprise and Business

The above announcement did not go into greater detail about how the specific Dynamics 365 offerings would be tailored. One of the advantages of the other offerings within the Office 365 range of products is the separation of business and enterprise plans. These typically allow for a reduced total cost of ownership for organisations under a particular size within an Office 365 plan, typically with an Enterprise version of the same plan available with (almost) complete feature parity, but with no seat limits. With this in mind, it makes sense that the initial detail in late 2016 confirmed the introduction of business and enterprise Dynamics 365 plans. As part of this, the CRM aspect of the offering would have sat firmly within the Enterprise plan, with – you guessed it – Enterprise pricing to match. The following article from encore at the time provides a nice breakdown of each offering and the envisioned target audience for each. Thus, we saw the introduction of Dynamics 365 for Enterprise as a replacement term for Dynamics CRM.

Perhaps understandably, when many businesses – typically used to paying £40-£50 per seat for their equivalent Dynamics CRM licenses – discovered that they would have to move to Enterprise plans and pricing significantly in excess of what they were paying, there were some heads turned. Microsoft Partners also raised a number of concerns with the strategy, which is why it was announced that the Business edition and Enterprise edition labels were being dropped. Microsoft stated that they would:

…focus on enabling any organization to choose from different price points for each line of business application, based on the level of capabilities and capacity they need to meet their specific needs. For example, in Spring 2018, Dynamics 365 for Sales will offer additional price point(s) with different level(s) of functionality.

The expressed desire to enable organisations to “choose” what they want goes back to what I mentioned at the start of this post – providing a billing/pricing mechanism that would support the modular nature of the late Dynamics CRM product. Its introduction as a concept at this stage comes a little late in the whole conversation regarding Dynamics 365 and represents an important turning point in defining the vision for the product. Whether this took feedback from partners/customers or an internal realisation to bring this about, I’m not sure. But it’s arrival represents the maturity in thinking concerning the wider Dynamics 365 offering.

Dynamics 365 for Customer Engagement

Following the retirement of the Business/Enterprise monikers and, in a clear attempt to simplify and highlight the CRM aspect of Dynamics 365, the term Customer Engagement started to pop-up across various online support and informational posts. I cannot seem to locate a specific announcement concerning the introduction of this wording, but its genesis appears to be early or mid-2017. The problem is that I don’t think there is 100% certainty yet on how the exact phrasing of this terminology should be used.

The best way to emphasise the inconsistency is to look to some examples. The first is derived from the name of several courses currently available on the Dynamics Learning Portal, published this year:

Now, take a look at the title and for the following Microsoft Docs article on impending changes to the application:

Notice it yet? There seems to be some confusion about whether for should be used when referring to the Customer Engagement product. Whilst the majority of articles I have found online seem to suggest that Dynamics 365 Customer Engagement is the correct option, again, I cannot point to a definitive source that states without question the correct phraseology that should be used. Regardless, we can see here the birth of the Customer Engagement naming convention, which I would argue is a positive step forward.

The Present Day: Customer Engagement and it’s 1:N Relationships

Rather handily, Customer Engagement takes us straight through to the present. Today, when you go to the pricing website for Dynamics 365, the following handy chart is presented that helps to simplify all of the various options available across the Dynamics 365 range:

This also indirectly confirms a few things for us:

  • Microsoft Dynamics 365 Customer Engagement and not Microsoft Dynamics 365 for Customer Engagement looks to be the approved terminology when referring to what was previously Dynamics CRM.
  • Microsoft Dynamics 365 is the overarching name for all modules that form a part of the overall offering. It has, by the looks of things, replaced the original Dynamics 365 for Enterprise designation.
  • The business offering – now known as Dynamics 365 Business Central – is in effect a completely separate offering from Microsoft Dynamics 365.

When rolled together, all of this goes a long way towards providing the guidance needed to correctly refer to the whole, or constituent parts, of the entire Dynamics 365 offering.

With that being said, can it be reliably said that the naming “crisis” has ended?

My key concern through all of this is a confusing and conflicting message being communicated to customers interested in adopting the system, to the potential end result of driving them away to competitor systems. This appears to have been the case for about 1-2 years since the original Dynamics 365 announcement, and a large part of this can perhaps be explained by the insane acquisition drive in 2015/6. Now, with everything appearing to slot together nicely and the pricing platform in place to support each Dynamics 365 “module” and the overall offering, I would hope that any further change in this area is minimal. As highlighted above though, there is still some confusion about the correct replacement terminology for Dynamics CRM – is it Dynamics 365 Customer Engagement or Dynamics 365 for Customer Engagement? Answers on a postcode, please!

Another factor to consider amongst all of this is that naming will constantly be an issue should Microsoft go through another cycle of acquisitions focused towards enhancing the Dynamics 365 offering. Microsoft’s recent acquisition plays appear to be more focused towards providing cost optimization services for Azure and other cloud-based tools, so it can be argued that a period of calm can be expected when it comes to incorporating acquired ISV solutions into the Dynamics 365 product range.

I’d be interested to hear from others on this subject, so please leave a comment below if you have your own thoughts on the interesting journey from Dynamics CRM to Dynamics 365 Customer Engagement

After going through a few separate development cycles involving Dynamics 365 Customer Engagement (D365CE), you begin to get a good grasp of the type of tasks that need to be followed through each time. Most of these are what you may expect – such as importing an unmanaged/managed solution into a production environment – but others can differ depending on the type of deployment. What ultimately emerges as part of this is the understanding that there are certain configuration settings and records that are not included as part of a Solution file and which must be migrated across to different environments in an alternate manner.

The application has many record types that fit under this category, such as Product or Product Price List. When it comes to migrating these record types into a Production environment, those out there who are strictly familiar with working inside the application only may choose to utilise the Advanced Find facility in the following manner:

  • Generate a query to return all of the records that require migration, ensuring all required fields are returned.
  • Export out the records into an Excel Spreadsheet
  • Import the above spreadsheet into your target environment via the Data Import wizard.

And there would be nothing wrong with doing things this way, particularly if your skillset sits more within a functional, as opposed to technical, standpoint. Where you may come unstuck with this approach is if you have a requirement to migrate Subject record types across environments. Whilst a sensible (albeit time-consuming) approach to this requirement could be to simply create them from scratch in your target environment, you may fall foul of this method if you are utilising Workflows or Business Rules that reference Subject values. When this occurs, the application looks for the underlying Globally Unique Identifier (GUID) of the Subject record, as opposed to the Display Name. If a record with this exact GUID value does not exist within your target environment, then your processes will error and fail to activate. Taking this into account, should you then choose to follow the sequence of tasks above involving Advanced Find, your immediate stumbling block will become apparent, as highlighted below:

As you can see, there is no option to select the Subject entity for querying, compounding any attempts to get them exported out of the application. Fortunately, there is a way to get overcome this via the Configuration Migration tool. This has traditionally been bundled together as part of the applications Solution Developer Kit (SDK). The latest version of the SDK for 8.2 of the application can be downloaded from Microsoft directly, but newer versions – to your delight or chagrin – are only available via NuGet. For those who are unfamiliar with using this, you can download version 9.0.2.3 of the Configuration Migration tool alone using the link below:

Microsoft.CrmSdk.XrmTooling.ConfigurationMigration.Wpf.9.0.2.3

With everything downloaded and ready to go, the steps involved in migrating Subject records between different D365CE environments are as follows:

  1. The first step before any export can take place is to define a Schema – basically, a description of the record types and fields you wish to export. Once defined, schemas can be re-used for future export/import jobs, so it is definitely worth spending some time defining all of the record types that will require migration between environments. Select Create schema on the CRM Configuration Migration screen and press Continue.

  1. Login to D365CE using the credentials and details for your specific environment.

  1. After logging in and reading your environment metadata, you then have the option of selecting the Solution and Entities to export. A useful aspect to all of this is that you have the ability to define which entity fields you want to utilise with the schema and you can accommodate multiple Entities within the profile. For this example, we only want to export out the Subject entity, so select the Default Solution, the entity in question and hit the Add Entity > button. Your window should resemble the below if done correctly:

  1. With the schema fully defined, you can now save the configuration onto your local PC. After successfully exporting the profile, you will be asked whether you wish to export the data from the instance you are connected to. Hit Yes to proceed.

  1. At this point, all you need to do is define the Save to data file location, which is where a .zip file containing all exported record data will be saved. Once decided, press the Export Data button. This can take some time depending on the number of records being processed. The window should update to resemble the below once the export has successfully completed. Select the Exit button when you are finished to return to the home screen.

  1. You have two options at this stage – either you can either exit the application entirely or, if you have your target import environment ready, select the Import data and Continue buttons, signing in as required.

  1. All that remains is to select the .zip file created in step 5), press the Import Data button, sit back and confirm that all record data imports successfully.

It’s worth noting that this import process works similarly to how the in-application Import Wizard operates with regards to record conflicts; namely, if a record with the same GUID value exists in the target instance, then the above import will overwrite the record data accordingly. This can be helpful, as it means that changes to records such as the Subject entity can be completed safely within a development context and promoted accordingly to new environments.

The Configuration Migration tool is incredibly handy to have available but is perhaps not one that it is shouted from the rooftops that often. It’s usefulness not just extends to the Subject entity, but also when working with the other entity types discussed at the start of this post. Granted, if you do not find yourself working much with Processes that reference these so-called “configuration” records, then introducing the above step as part of any release management process could prove to be an unnecessary administrative burden. Regardless, there is at least some merit to factor in the above tool as part of an initial release of a D365CE solution to ensure that all development-side configuration is quickly and easily moved across to your production environment.

Very much like a stopped clock telling the correct time twice a day, you can guarantee there will be two Dynamics 365 Customer Engagement releases each year. The first such occasion this year has come around quickly, with Microsoft setting out the stall for the Spring 2018 release earlier this week. The headline messages around this release are all around providing reassurance that the application is GDPR ready and in emphasising the maturity of Power Apps & Microsoft Flow as products within their own right and in conjunction with Dynamics 365. I’ve been studying the release notes in greater detail and, as part of this week’s blog post, I wanted to delve underneath the headlines and extrapolate some of the less touted, but potentially most impactful, new features that I am most looking forward to.

Answer Tags for Voice of the Customer Surveys

I made a commitment earlier this year to utilise the Voice of the Customer solution more. When used correctly, and if you are already heavily invested in Dynamics 365, the solution can present a straightforward and cost-effective way of starting to understand what customers are thinking, both with respect to specific experiences they have with your business and towards the organisation overall. One new feature to be introduced with Voice of the Customer, which I am looking forward to getting my hands on, is the ability to use Answer Tags to dynamically structure any subsequent questions within the survey. A good example of how this works in practice can be seen below, as shown in the release notes:

The key driver behind the automation of customer feedback tools should be to ensure that customers receive tailored and relevant surveys relating to services they have received, whilst also taking away any administrative headache when distributing and collating feedback answers. The feature above helps to solidify the benefits that Voice of the Customer can deliver when utilised in tandem with Dynamics 365 Customer Engagement, as well as allowing for more powerful and broadly applicable surveys to be structured at design time.

The rise of the Unified Interface

The rebrand of the entire Dynamics 365 Customer Engagement application has been much promised and touted over the past year. With this release, it becomes a reality. Pretty much every key application module – Customer Service, Sales, Field Service & Project Service Automation – has been updated to utilise the new Unified Interface. The following applications/solutions will also be Unified Interface ready as part of the release:

  • Dynamics 365 App for Outlook
  • LinkedIn Sales Navigator
  • Gamification

The Unified Interface is very much an offshoot of the Interactive Service Hub, which it now replaces fully as part of this release (Interactive Service Hub users should read this article carefully, as there are some important points to consider if you plan to upgrade in the near future). I saw the new unified interface in action when attending the CRMUG Meeting in Reading last year, and its introduction represents one of the ways Microsoft is investing heavily within the Dynamics 365 product moving forward. Its key benefits in comparison to the current experience can be summarised as follows:

  • Consistent end-user experience when accessing the application from desktop, mobile or tablet operating systems.
  • Fully mobile responsive template, that adjusts to your specific device to provide the optimal experience
  • Better utilisation of empty spacing across entity views, forms etc.

With this release, administrators and developers need to start actively considering the impact the Unified Interface has on their systems and plan accordingly. Whilst I imagine there to be some pain involved as part of this, the end result – a much crisper and effective end-user interface – is worth the trade-off.

PowerShell Management for PowerApps

Up until now, your options for the automation of administrative tasks for PowerApps were limited. This issue was addressed to a certain extent for Dynamics 365 Customer Engagement Online very recently, via the introduction of PowerShell modules to facilitate organisation backups, instance resets and/or administrative mode toggling. These types of tools can go a long way if you have implemented automated release management tools for your various environments, taking human error out of the equation and streamlining deployments.

PowerApps looks to be going in the right direction in this regard, as the Spring Wave release will introduce a set of cmdlets that allow for the following actions to be accomplished:

  • Environments and environment permissions
  • PowerApps and app permission
  • Flows and flow permissions
  • Export and import of resource packages across environments
  • PowerApps and Flow licenses report (of active users)

Whilst definitely more administrative as opposed to deployment focused, their introduction is no doubt a welcome step in the right direction.

Future of the Common Data Service

Microsoft released the Common Data Service (CDS) in late 2016, around the same time as Microsoft Flow and the Dynamics CRM rebrand. The premise was simple and admirable: a common framework for you to develop the data you need for your business, that is instantly re-usable across multiple applications. My chief concern when this was first announced is where this left the traditional customisation experience for Dynamics CRM/365 Customer Engagement, commonly referred to as xRM. Having to countenance potential redevelopments of “legacy” xRM systems, just to make them compatible with the CDS could prove to be a costly and unnecessary exercise; this can perhaps be summed up best by the old saying “If it ain’t broke, don’t fix it!”.

There seems to have been a recognition of this dilemma as part of this release, with the following announcement regarding the Common Data Service and PowerApps specifically:

This release also includes major advancements to the Common Data Service for Apps (the data platform that comes with PowerApps) and client UX creation tools. These new capabilities are backward-compatible with the Dynamics 365 platform (frequently called the xRM platform), which means that Dynamics 365 customizers and partners can use already-acquired skills to create apps with PowerApps.

What I think this means, in simple terms, is that the customisation experience between Dynamics 365 Customer Engagement and Power Apps will, in time, become virtually indistinguishable. And this is great for a number of reasons – it negates any excuse that individuals/organisations may raise to explore PowerApps further, gives us the ability to quickly develop our own custom mobile applications for our particular Dynamics 365 solution and provides an easy framework to unify business data across multiple applications. This very much parallels the intended experience that Power BI has for traditional Excel users – namely, providing an identical toolbox that can be leveraged to quickly deploy solutions with reduced technical debt. As with a lot of these announcements, we’re not going to know exactly how things operate until they are in our hands, but the immediate upshot appears to be the nullification of any new learning requirements for CDS.

If you are looking for further detail regarding this change, then the ever so excellent Jukka Niiranen has published a blog post which really breaks down the detail behind this better than I ever could 🙂

Yes, XRM Is The New Common Data Service

Email Notifications for Microsoft Flow Failures

Similar to Voice of the Customer, I also promised myself to use Microsoft Flow more this year. After some uneventful early testing, the tool has become (for me) an indisposable means of achieving integration requirements that would traditionally require custom code and a dedicated server environment to execute. Microsoft Flows do get some much-deserved love and attention as part of this release, and the one new feature which I think is going to be of the biggest help is email notifications for flow failures. The announced feature details are as follows:

Enable email notifications to detect flow failures. To enable this feature, go to the Flow details page, and then, on the contextual menu (…), subscribe to receiving emails about flow failures. These useful email notifications provide:

  • Information about why your flow failed.

  • Meaningful remediation steps.

  • Additional resources to help you build robust flows that never fail.

There’s so much more about this release that you could talk for days about…

…but I would be unsure whether anyone would still be listening by the end! You can dive into the detail behind each of the above highlights and what else to expect in the next release by downloading the release notes yourself. Let me know in the comments below what you are looking forward to the most as part of the next release.

This is an accompanying blog post to my YouTube video Dynamics 365 Customer Engagement Deep Dive: Creating a Basic Custom Workflow Assembly. The video is part of my tutorial series on how to accomplish developer focused tasks within Dynamics 365 Customer Engagement. You can watch the video in full below:

Below you will find links to access some of the resources discussed as part of the video and to further reading topics:

PowerPoint Presentation (click here to download)

Full Code Sample

using System;
using System.Activities;

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using Microsoft.Xrm.Sdk.Query;

namespace D365.SampleCWA
{
    public class CWA_CopyQuote : CodeActivity
    {
        protected override void Execute(CodeActivityContext context)
        {
            IWorkflowContext c = context.GetExtension<IWorkflowContext>();

            IOrganizationServiceFactory serviceFactory = context.GetExtension<IOrganizationServiceFactory>();
            IOrganizationService service = serviceFactory.CreateOrganizationService(c.UserId);

            ITracingService tracing = context.GetExtension<ITracingService>();

            tracing.Trace("Tracing implemented successfully!", new Object());

            Guid quoteID = c.PrimaryEntityId;

            Entity quote = service.Retrieve("quote", quoteID, new ColumnSet("freightamount", "discountamount", "discountpercentage", "name", "pricelevelid", "customerid", "description"));

            quote.Id = Guid.Empty;
            quote.Attributes.Remove("quoteid");

            quote.Attributes["name"] = "Copy of " + quote.GetAttributeValue<string>("name");
            Guid newQuoteID = service.Create(quote);

            EntityCollection quoteProducts = RetrieveRelatedQuoteProducts(service, quoteID);
            EntityCollection notes = RetrieveRelatedNotes(service, quoteID);

            tracing.Trace(quoteProducts.TotalRecordCount.ToString() + " Quote Product records returned.", new Object());

            foreach (Entity product in quoteProducts.Entities)
            {
                product.Id = Guid.Empty;
                product.Attributes.Remove("quotedetailid");
                product.Attributes["quoteid"] = new EntityReference("quote", newQuoteID);
                service.Create(product);
            }
            foreach (Entity note in notes.Entities)
            {
                note.Id = Guid.Empty;
                note.Attributes.Remove("annotationid");
                note.Attributes["objectid"] = new EntityReference("quote", newQuoteID);
                service.Create(note);
            }
        }

        [Input("Quote Record to Copy")]
        [ReferenceTarget("quote")]

        public InArgument<EntityReference> QuoteReference { get; set; }
        private static EntityCollection RetrieveRelatedQuoteProducts(IOrganizationService service, Guid quoteID)
        {
            QueryExpression query = new QueryExpression("quotedetail");
            query.ColumnSet.AllColumns = true;
            query.Criteria.AddCondition("quoteid", ConditionOperator.Equal, quoteID);
            query.PageInfo.ReturnTotalRecordCount = true;

            return service.RetrieveMultiple(query);
        }
        private static EntityCollection RetrieveRelatedNotes(IOrganizationService service, Guid objectID)
        {
            QueryExpression query = new QueryExpression("annotation");
            query.ColumnSet.AllColumns = true;
            query.Criteria.AddCondition("objectid", ConditionOperator.Equal, objectID);
            query.PageInfo.ReturnTotalRecordCount = true;

            return service.RetrieveMultiple(query);
        }
    }
}

Download/Resource Links

Visual Studio 2017 Community Edition

Setup a free 30 day trial of Dynamics 365 Customer Engagement

C# Guide (Microsoft Docs)

Source Code Management Solutions

Further Reading

Microsoft Docs – Create a custom workflow activity

MSDN – Register and use a custom workflow activity assembly

MSDN – Update a custom workflow activity using assembly versioning (This topic wasn’t covered as part of the video, but I would recommend reading this article if you are developing an ISV solution involving custom workflow assemblies)

MSDN – Sample: Create a custom workflow activity

You can also check out some of my previous blog posts relating to Workflows:

  • Implementing Tracing in your CRM Plug-ins – We saw as part of the video how to utilise tracing, but this post goes into more detail about the subject, as well as providing instructions on how to enable the feature within the application (in case you are wondering why nothing is being written to the trace log 🙂 ). All code examples are for Plug-ins, but they can easily be repurposed to work with a custom workflow assembly instead.
  • Obtaining the User who executed a Workflow in Dynamics 365 for Customer Engagement (C# Workflow Activity) – You may have a requirement to trigger certain actions within the application, based on the user who executed a Workflow. This post walks through how to achieve this utilising a custom workflow assembly.

If you have found the above video useful and are itching to learn more about Dynamics 365 Customer Engagement development, then be sure to take a look at my previous videos/blog posts using the links below:

Have a question or an issue when working through the code samples? Be sure to leave a comment below or contact me directly, and I will do my best to help. Thanks for reading and watching!

As part of developing Dynamics CRM/Dynamics 365 Customer Engagement (CRM/D365CE) plug-ins day in, day out, you can often forget about the Execution Mode setting. This can be evidenced by the fact that I make no mention of it in my recent tutorial video on plug-in development. In a nutshell, this setting enables you to customise whether your plug-in executes in Synchronous or Asynchronous mode. Now, you may be asking – just what the hell does that mean?!? The best way of understanding is by rephrasing the terminology; it basically tells the system when you want your code to be executed. Synchronous plug-ins execute all of your business logic whilst the record is being saved by the user, with this action not being considered complete and committed to the backend database until the plug-in completes. By comparison, Asynchronous plug-ins are queued for execution after the record has been saved. A System Job record is created and queued alongside other jobs in the system via the Asynchronous Service. Another way of remembering the difference between each one is to think back to the options available to you as part of a Workflow. They can either be executed in real time (synchronously) or in the background (asynchronously). Plug-ins are no different and give you the flexibility to ensure your business logic is applied immediately or, if especially complex, queued so that the system has sufficient time to process in the background.

I came across a strange issue with an arguably even stranger Synchronous plug-in the other day, which started failing after taking an inordinately long time saving the record:

Unexpected exception from plug-in (Execute): MyPlugin.MyPluginClass: System.AggregateException: One or more errors occurred.

The “strange” plug-in was designed so that, on the Create action of an Entity record, it goes out and creates various related records within the application, based on a set of conditions. We originally had issues with the plug-in a few months back erroring, due to the execution time exceeding the 2 minute limit for sandbox plug-ins. A rather ingenious and much more accomplished developer colleague got around the issue by implementing a degree of asynchronous processing within the plug-in, achieved like so:

await Task.Factory.StartNew(() =>
{
    lock (service)
    {
        Stopwatch stopwatch = Stopwatch.StartNew();
        Guid record = service.Create(newRecord);
        tracing.Trace("Record with ID " + record.ToString() + " created successfully after: {0}ms.", stopwatch.ElapsedMilliseconds);
    }
});

I still don’t fully understand just exactly what this is doing, but I put this down to my novice level C# knowledge 🙂 The important thing was that the code worked…until some additional processing was added to the plug-in, leading to the error message above.

At this juncture, our only choice was to look at forcing the plug-in to execute in Asynchronous mode by modifying the appropriate setting on the plug-in step within the Plugin Registration Tool:

After making this change and attempting to create the record again in the application, everything worked as expected. However, this did create a new problem for us to overcome – end users of the application were previously used to seeing the related records created by the plug-in within sub-grids on the Primary Entity form, which would then be accessed and worked through accordingly. As the very act of creating these records now took place within the background and took some time to complete, we needed to display an informative message to the user to advise them to refresh the form after a few minutes. You do have the ability within plug-ins to display a custom message back to the user, but this is only in situations where you are throwing an error message and it didn’t seem to be a particularly nice solution for this scenario.

In the end, the best way of achieving this requirement was to implement a JScript function on the form. This would trigger whenever the form is saved and displays a message box that the user has to click OK on before the save action is carried out:

function displaySaveMessage(context) {

    var eventArgs = context.getEventArgs();
    var saveMode = eventArgs.getSaveMode();

    if (saveMode == 70 || saveMode == 2 || saveMode == 1 || saveMode == 59) {
        var message = "Records will be populated in the background and you will need to refresh the form after a few minutes to see them on the Sub-Grid. Press OK to save the record."
        Xrm.Utility.alertDialog(message, function () {
            Xrm.Page.data.save().then(function () {
                Xrm.Page.data.refresh();
            })
        });
    }
}

By feeding through the execution context parameter, you are able to determine the type of save action that the alert will trigger on; in this case, SaveSave & CloseSave & New and Autosave. Just make sure you configure your script with the correct properties on the form, which are:

  • Using the OnSave event handler
  • With the Pass execution context as first parameter setting enabled

From the end-users perspective, they will see something similar to the below when the record is saved:

It’s a pity that we don’t have similar kind of functionality exposed via Business Rules that enable us to display OnSave alerts that are more in keeping with the applications look and feel. Nevertheless, the versatility of utilising JScript functions should be evident here and can often achieve these types of bespoke actions with a few lines of code.

When it comes to plug-in development, understanding the impact and processing time that your code has within the application is important for two reasons – first, in ensuring that end users are not frustrated by long loading times and, secondly, in informing the choice of Execution Mode when it comes to deploying out a plug-in. Whilst Asynchronous plug-ins can help to mitigate any user woes and present a natural choice when working with bulk operations within the application, make sure you fully understand the impact that these have on the Asynchronous Service and avoid a scenario where the System Job entity is queued with more jobs then it can handle.