ExecuteMultipleRequest and ExecuteTransactionRequest in Dynamics 365 CE

There are scenarios in which you will be integrating with the Common Data Service from outside the platform. This could be a console application designed to create records or an integration process designed to send data from an external system into Dynamics 365 CE. Creating, Updating or Deleting data on a single record basis could adversely affect performance and reach your organization’s API limits.

The API limits only apply to online instances. Due to the shared nature of the online hosts, the limits are put in place by Microsoft to ensure the stability of the online platform for all customers. Microsoft limits the number of concurrent requests as well as limiting the number of requests per user. The request per user limit is 60,000 API calls in five minutes, subject to change. Microsoft doesn’t specify the number of concurrent requests, but the ExecuteMultipleRequest does state that it is limited to two concurrent connections. If the API limits are exceeded, a FaultException is returned.

There are two useful messages in the SDK that reduce the number of API calls by executing requests in bulk. ExecuteMultipleRequest and ExecuteTransactionRequest both execute batch requests against the API. Both messages have a batch size limit of 1000 calls and two concurrent connections, so you may need to use multiple batches to complete your calls. An ExecuteTransactionRequest will execute all calls in a single transaction, rolling back if an error has occurred. ExecuteMultipleRequest is not in a transaction and it will not rollback previously completed requests if an error occurs. ExecuteMultipleRequests can be configured to either stop processing when the first error is received or continue processing, keeping a record of each failed call.

Note that an ExecuteMultipleRequest is allowed to contain one or more ExecuteTransactionRequest calls, but an ExecuteTransactionRequest cannot contain any ExecuteMultipleRequests. ExecuteMultipleRequests cannot include another ExecuteMultipleRequest nor can an ExecuteTransactionRequest include another ExecuteTransactionRequest. Neither of these messages should be used in plugins or custom workflow activities, as they will adversely affect performance and could trigger the two-minute channel timeout exception.

Microsoft guidance on when to use ExecuteMultipleRequest or ExecuteTransactionRequest is:

  • Use ExecuteMultipleRequest to bulk load data or external processes that are intentional about executing long-running operations (greater than two minutes).
  • Use ExecuteMultipleRequest to minimize the round trips between custom client and Dynamics 365 servers, thereby reducing the cumulative latency incurred.
  • Use ExecuteTransactionRequest for external clients that require the batch of operations to be committed as a single, atomic database transaction or rollback if any exception is encountered. Be aware of the potential for database blocking for the duration of the long-running transaction.

Using ExecuteMultipleRequest and ExecuteTransactionRequest are both good methods for reducing the number of API calls as well as increasing the performance of external calls. Neither is meant to be used from within plugins nor custom workflow activities. To learn how to use these methods, and to view sample code, use the Microsoft Docs references listed below.

Overview of Dynamics 365 for Customer Service

My study of MB-900 is continuing with an overview of Dynamics 365 for Customer Service. Where Dynamics 365 for Sales was focused on helping the sales associates build stronger and lasting relationships with customers, Dynamics 365 for Customer Service is focused on providing flexibility and a consistent level of service for customers. Support agents will be able to use Dynamics 365 for Customer Service to better optimize their time and deliver the right answers to the customer quicker.

As with Dynamics 365 for Sales, Dynamics 365 for Customer Service contains customizable interactive dashboards. These dashboards will keep track of support queues, knowledge articles, and current cases. Support agents can use these dashboards to quickly and dynamically determine which are the highest priority cases to follow up on. Once the case is identified and opened, a customized case resolution process will help them find the tools and information that the support agent will need in order to properly assist the customer.

Customer Service diagram from Microsoft Learn
Customer Service diagram from Microsoft Learn

In Dynamics 365 for Customer Service, a customer has an entitlement, also known as a support contract. This entitlement defines the level of support the customer can receive over a one-year period of time. The entitlement can include the number of support cases that can be opened as well as how long it takes for a support agent to respond to the case.

An omnichannel support solution is provided by Dynamics 365 for Customer Service. This gives the customer multiple different methods of interacting with the service center each with a consistent experience, regardless of the method they choose. These methods include online customer support portals that can be accessed from a computer or mobile device; integrated chat that has a service bot answering basic questions and recording them for the support agent to take over; email support queues; and phone calls direct to the service center.

When customers interact with the portal, online chat, or email the service center, a case is automatically created in Dynamics 365 for Customer Service. This case is compared to the customer’s entitlement to determine which queue the case is assigned. From that point, a support agent that has access to the queue can pick up the case and start working it. That support agent is then responsible for working the case until it is resolved. Other support agents will be able to see that the case is being handled, and can pick up the next case in the queue.

The support agent is given several tools to assist them in resolving the case. A case resolution process is automatically assigned to the case, based on the type of case. This process is customized by the business and contains several stages, each with multiple steps to be completed in order to resolve the case. Integrated knowledge base articles are offered to the support agent and can be emailed to the customer with possible resolutions.

Once the customer confirms that their problem has been resolved, the support agent is able to close the case as resolved. With the case resolved, the entitlement is updated. If the entitlement includes a specified number of support cases available to the customer, that number is decremented by one to reflect the number of cases they have remaining.

Demo of the customer support process in Dynamics 365 for Customer Service.

Demo of the customer support portal in Dynamics 365 for Customer Service.

Using Extension Methods in Dynamics 365 CE Plugins

In my previous blog post, Extension Methods in the .NET Framework, I covered how to use extension methods in C# and VisualBasic to extend the functionality of base types. Using extension methods can also be useful when writing plugins for Dynamics 365 Customer Engagement (Dynamics CRM). I create my own library of extension methods that can be used as needed for any project I’m currently working on. The most common types of extensions for me involves the tracing service, the organization service, and the entity.

I have two types of tracing that I perform. The first is standard trace messages that are always logged to the plugin trace logs. The second is a debug-only trace message that only writes to the plugin trace log if the assembly is compiled in Debug as opposed to Release. As a side comment, it is always preferable to have your assemblies compiled in Release mode when deployed to a production ready environment, to improve plugin performance. This makes using the #if DEBUG preprocessing directive more effective.

Without an extension message, sending a message to the plugin tracing log is done by calling the Trace method of Microsoft.Xrm.Sdk.ITracingService.

using Microsoft.Xrm.Sdk;

public namespace Sample.Tracing
{
    public class PluginTest : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            tracingService.Trace("Entering plug-in execution.");
            tracingService.Trace("Some debug information is logged to the plugin trace log.");
            // Additional code goes here
        }
    }
}

The standard way of tracing is effective on its own but is still missing some elements that make it useful. As mentioned previously, you may only want certain tracing calls to be done if you are actively debugging your code. Prepending every call to the trace log with a time stamp is also beneficial when trying to determine where plug-in performance is being adversely impacted. You can also parse your error object to output more detailed error messages directly to the plugin trace logs. For the sample below, I’m just going to demonstrate how we can expand the tracing log to handle debug only messages and time-stamped messages.

using Microsoft.Xrm.Sdk;
using System;

namespace Sample.SdkExtensions
{
    public static class ExtITracingService
    {
        public static void DebugMessage(this ITracingService tracingService, string format, params object[] args)
#if DEBUG
            => tracingService.LogMessage(format, args);
#else
            { }
#endif
    }

    public static void LogMessage(this ITracingService tracingService, string format, params object[] args)
    {
        string message = (args == null || args.Length == 0)
            ? format
            : String.Format(format, args);
        tracingService.Trace("{0}: {1}", DateTime.Now.ToString("o"), message);
    }
}

The DebugMessage extension method shows how to use the preprocessing directive to only execute when running in Debug mode. If the code is running in Debug, then it will call the LogMessage extension method. If it isn’t, then the method doesn’t do anything at all. This will allow us to have more detailed messages when running the assembly in Debug, and better performance when running the assembly in Release. The LogMessage extension method will create the appropriate message string from the format and optional arguments and pass that directly over to the ITracingService, prepended with a date and time stamp.

Now, we can update the plugin code to use our new extension methods.

using Sample.SdkExtensions;
using Microsoft.Xrm.Sdk;

public namespace Sample.Tracing
{
    public class PluginTest : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            tracingService.LogMessage("Entering plug-in execution.");
            tracingService.DebugMessage("Some debug information is logged to the plugin trace log.");
            // Additional code goes here
        }
    }
}

As you can see, once we have our extension method in the project, we can reference the namespace for it in our using statements. At that point, our DebugMessage and LogMessage extension methods are able to be used. Now, debug messages will only be added to the plugin tracing log if the assembly is compiled as Debug, and both messages will be prepended with the appropriate time stamp. These extension methods increase the readability and usability of the code, giving consistent logging functionality no matter where the calls are made in the code.

Extending the entity is another area that it is useful to create extension methods. Getting and setting of attribute values often requires the same several lines of code to retrieve the appropriate information. Examine the code below using the standard SDK calls to retrieve the primary contact Id from one account, and set it on another. While it is preferable to retrieve the Entity Reference in this type of scenario, I am writing in this fashion to show the value in reducing code complexity.

Guid entityReferenceId = account1.Contains("primarycontact")
    ? ((EntityReference)account1["primarycontact"]).Id
    : Guid.Empty;

if (entityReferenceId == Guid.Empty)
{
    if (account2.Contains("primarycontact"))
    {
        account2["primarycontact"] = null;
    }
}
else
{
    if (account2.Contains("primarycontact"))
    {
        account2["primarycontact"] = new EntityReference("contact", entityReferenceId);
    }
    else
    {
        account2.Attributes.Add("primarycontact") = new EntityReference("contact", entityReferenceId);
    }
}

There are several lines of code required to perform a simple get and set operation. These operations can be created as extension methods on Microsoft.Xrm.Sdk.Entity as we did for the tracing service. I won’t be putting the extension methods here, instead, I will show how we can use two new extension methods GetEntityReferenceId and SetEntityReference to increase the readability of the plugin code.

Guid entityReferenceId = account1.GetEntityReferenceId("primarycontact");
account2.SetEntityReference("contact", entityReferenceId);

As you can see, the extension methods now make it easier to set and get values from the entity image. As mentioned previously, this increases readability and reusability of the code, making debugging easier. Just be aware that if you are setting default values (such as Guid.Empty for Guid values) you’ll want to have additional checks in your code to ensure that you are working with the proper data.

The final extension method I will touch on in this entry is related to Microsoft.Xrm.Sdk.IOrganizationService. In my previous blog post, I mentioned that it is strongly discouraged from overloading the methods of existing types. In the case of extending the organization service, I am intentionally ignoring that advice. In this case, my extension methods are simply shortcuts that are passed to the primary call, and even if Microsoft later adds their own overloads that mirror what I have done, it won’t break my existing functionality. This is an exception to the recommendation that still needs to be handled with care.

// Global Values
EntityReference entityReference = new EntityReference("account", Guid.Parse("608DA112-2681-4967-B30E-A4132321010A")); // Normally will be retrieved from an entity.
string[] columnNames= new string[] { ..list of fields.. };

// Default SDK Retrieve call.
service.Retrieve(entityReference.LogicalName, entityReference.Id, new ColumnSet(columnNames));

// Overloaded extension Retrieve call.
service.Retrieve(entityReference, columnNames);

// The overload in from the extension static class
public static Entity Retrieve(this IOrganizationService service, EntityReference entityReference, string[] columnNames)
    => service.Retrieve(entityReference.LogicalName, entityReference.Id, new ColumnSet(columnNames));

As you can see, the overload is simply calling the SDK Retrieve method with the appropriate parameter values. No additional validation is being done. It simply allows for a shorter method call to simplify the code.

As mentioned in the previous article, there is no consensus on how often to use extension methods. Microsoft does recommend using “sparingly and only when you have to.” It could be argued that the SDK methods are simple enough and don’t fall under “when you have to.” In my case, I prefer having multiple overloads, as I find that it makes debugging the code easier. My methods become shorter and easier to read. I have additional tracing methods, beyond what is shown in this blog post, to give more details in the plugin trace log. The ultimate goal for me is the maintainability, reusability, and readability of my code. Using extension methods with the SDK achieves that for me.

Overview of Microsoft Relationship Sales

This blog post continues with the study related material for MB-900 and focuses on Microsoft Relationship Sales. Microsoft Relationship Sales is an additional module in Dynamics 365 which links LinkedIn Sales Navigator with Dynamics 365 for Sales by leveraging LinkedIn relationships and company information. This integration between LinkedIn and Dynamics 365 will allow sales associates access to powerful relationship information from within Dynamics 365 for Sales.

Unifying the Seller Experience from Microsoft Learn
Unifying the Seller Experience from Microsoft Learn

LinkedIn Sales Navigator integration allows users to see headlines, activities, news and other related information about their contact directly inside Dynamics 365. Users can see shared contacts in order to facilitate icebreakers and encourage introductions to new prospects. LinkedIn InMail and PointDrive can be shown as activities and the LinkedIn user images can be displayed directly inside Dynamics 365. All this information can then be used in Dynamics 365 sales playbooks and with the AI for sales to strengthen the relationships between the sales associate and their contacts.

Embedded Intelligence is included as part of Dynamics 365 for Sales and adds powerful features for helping to manage relationships with contacts, especially in conjunction with Microsoft Relationship Sales. This is a suite of features that works in conjunction with data stored in Dynamics 365 and Microsoft Exchange. These features include relationship assistant, email engagement and auto capture. Relationship assistant analyzes data to generate cards detailing recommended actions to take based on the current context of the user. Email engagement will help users to keep track of emails that are sent, viewed, responded to, as well as attachments and links viewed as activities. Auto capture analyzes relevant email addresses in Microsoft Exchange and tracks them from within Dynamics 365.

Embedded Intelligence Diagram from Microsoft Learn
Embedded Intelligence Diagram from Microsoft Learn

All the data collected from LinkedIn, Exchange, and Dynamics 365 can be uniquely analyzed with Dynamics 365 AI for Sales. The sales specific AI can analyze relationship information, predict lead and opportunity scores, analyze notes, and even offer talking points to customers and prospects.

Relationship Sales Video from Microsoft Learn

Overview of Dynamics 365 for Sales

Continuing with the study for MB-900 is an overview of Dynamics 365 for Sales. Dynamics 365 for Sales is built on top of Dynamics 365 Customer Engagement (CE) but is also available as an individual module at a lower cost per user. As the name implies, it is a sales focused application designed to help sales associates drive business and sales managers to dive deeper into the sales data generated.

Example Sales Process
Example Sales Process from Microsoft Learn

The image above, provided by Microsoft, shows an example of the typical sales process. The sales associate will start by qualifying leads. They contact the lead, gather information, and determine if the lead is a good fit, both for the potential customer and the organization as a whole. All actions, such as emails and phone calls, can be tracked against the lead. This information then becomes available to other sales associates and sales managers along the way. This process can be further enhanced by AI for Sales to create custom scoring models and analyze existing organization relationships to improve the likelihood of qualifying leads.

Once a lead is qualified, the lead can be converted to an opportunity. The lead can be linked to an existing contact and/or account. If one does not exist, it will be created and linked automatically during the qualification process. This begins the development cycle, where the opportunity is worked by determining what products and/or services are of interest to the customer. The data collected during this process can be tailored to meet the organizations unique business process flow. That data is then available to other team members on the opportunity record, increasing the chances of closing the opportunity. Like the lead, AI for Sales can be utilized to help increase the chances of closing the deal.

Once all the data is required and the products/services selected, a quote can be generated directly from the opportunity. This quote is sent as a proposal to the customer. The customer can then work with the sales associate to make any changes. Quotes are able to be revised and sent to the customer with the updated information. This feedback loop can happen several times through the life of the quote until the customer accepts the quote.

An accepted quote can automatically generate the sales order and the associated opportunity is closed as won. Integrations into other ERP systems can keep track of current inventory levels required to fulfill the sales order. Once the order is fulfilled, an invoice is generated in order to bill the customer. The invoice generation can come from Dynamics 365 for Sales, but it is not uncommon for it to come from the backend ERP system, such as Dynamics 365 Finance and Operations.

Video overview of Dynamics 365 for Sales from Microsoft Learn

While this process is similar among many organizations, it is by no means a unique process. Every organization has its own data points that are needed and their own strategies designed to qualify leads and close sales. Dynamics 365 for Sales allows for the creation of new fields and even new entities for gathering information. These new data points can be used in reports, shown on dashboards, and included anywhere in the sales process. With this data, whether from existing entities or custom entities, the industry and business requirements can be filled and the ability of the organization to drive business can be improved.

Introduction to Dynamics 365

As MB-900 is a test related to the fundamentals of Dynamics 365, it is essential to start with a basic introduction. Dynamics 365 is a collection of first-party business applications that are designed to help businesses simplify the complexity of CRM and ERP systems. They are modular business applications which work together on a single platform. Customer Engagement, Unified Operations, and Power Platform are the main areas of business applications for Dynamics 365. The individual business solutions are listed below:

  • Artificial Intelligence
  • Business Central
  • Customer Service
  • Field Service
  • Finance and Operations
  • Marketing
  • Mixed Reality
  • Project Service Automation
  • Retail
  • Sales
  • Talent

By leveraging one or more of these applications, organizations are able to engage customers more effectively, optimize business operations, empower employees to work better and more efficiently, as well as transform products and services by using data to find new opportunities and analyze customer data.

Microsoft Dynamics 365 Customer Engagement Certification

I started working with Microsoft Dynamics CRM 4.0 ten years ago. Five years ago I received my first Microsoft certifications for Dynamics CRM 2013. Times and technologies continue to grow, and with it, the offerings and skills needed to customize and develop on the platform correctly. What I knew as Microsoft Dynamics CRM, is now known as Microsoft Dynamics 365 Customer Engagement (CE), and is part of the broader Dynamics 365 suite of applications. To stay relevant with Microsoft’s offerings, I have to move beyond what I learned over the past ten years and begin to look into Azure, Power Platform, and the other products contained under the Dynamics 365 umbrella.

For this reason, I am studying to gain new certifications for Dynamics 365 CE and looking across the spectrum. The current exams I am studying for are MB-900, MB-200, MB-210, MB-220, MB-230, and MB-240. All these exams are geared towards functional consultants but are undoubtedly beneficial to software architects as well. I will be refreshing my knowledge of the entire suite of products, touching cloud computing, and looking at the Power Platform. As Microsoft introduces more exams geared toward developers, I will turn my focus to those exams as well. With this blog refresh, I plan on sharing my studies here. I even plan to create quizzes to test my knowledge, and to allow readers to test their own as well. I hope others will be able to benefit from this information and be able to find ways to pass it on to others in their sphere of influence.