Sunday, November 10, 2019

Plugin Shared Variables

Shared Variables
Microsoft Dynamics 365 Customer Engagement platform and the execution pipeline provides the ability to pass data from one plug-in to another through an IPluginExecutionContext property called SharedVariables. This property is a collection of key/value pairs which developers can use to share data between plug-ins which are registered on both the pre and post events.
Shared Variables are useful for sharing the data during complex Plug-in development by sharing the data between Plugins registered on both the pre and post events.
Any value stored in the Plug-in context of Pre-event will be available in the Post-event of the Plug-in. This way, we can avoid storing the values in a custom attribute. Certain data validation which needs to be done at post-event can be achieved by passing the value from Pre-event of the Plug-in.


Test Case: For a demo, let’s say We want to check the if the contact being created is duplicate i.e. contact exists with same first name and last name in Customer Engagement. If it exists, on post-operation, we want to mark the contact status duplicate.
Below is a sample code where we are passing a flag if we found this contact duplicate from a pre-event plugin and retrieving the shared variables from the post-event plugin and change status:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Crm.Sdk.Messages;

namespace TestPlugin
{
 public class PreEventPlugin : IPlugin
 {
  public void Execute(IServiceProvider serviceProvider)
  {
  // Obtain the execution context from the service provider.
  Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
  serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
  IOrganizationService service = ((IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory))).CreateOrganizationService(new Guid?(context.UserId));
  if ((context.InputParameters.Contains("Target")) && (context.InputParameters["Target"] is Entity) && context.MessageName.ToUpper() == "UPDATE")
  {
   Entity entity = (Entity)context.InputParameters["Target"];
   String sFirstName = entity.GetAttributeValue<String>("firstname");
   String sLastName = entity.GetAttributeValue<String>("lastname");
   
   QueryExpression qe = new QueryExpression("contact");
   qe.Criteria.AddCondition("firstname", ConditionOperator.Equal, sFirstName);
   qe.Criteria.AddCondition("lastname", ConditionOperator.Equal, sLastName);
   EntityCollection enColl = service.RetrieveMultiple(qe);
   if (enColl.Entities.Count >= 1)
   {
    // variable named isDuplicate
    context.SharedVariables.Add("isDuplicate", true);
    }
   }
   }
  }

 public class PostEventPlugin : IPlugin
  {
  public void Execute(IServiceProvider serviceProvider)
  {
  // Obtain the execution context from the service provider.
  Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
  serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
  IOrganizationService service = ((IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory))).CreateOrganizationService(new Guid?(context.UserId));
  
  if ((context.InputParameters.Contains("Target")) && (context.InputParameters["Target"] is Entity) && context.MessageName.ToUpper() == "UPDATE")
  {
   Entity entity = (Entity)context.InputParameters["Target"];
   // Obtain the contact from the execution context shared variables.
   Boolean isDuplicate = (Boolean)context.SharedVariables["isDuplicate"];
   if (isDuplicate)
   {
    //update status to duplicate
    Entity en = new Entity("contact");
    en.Id = entity.Id;
    en["statuscode"] = new OptionSetValue(100000000);//Duplicate (custom value)
    service.Update(en);
    }
   }
  }
 }
}
Your plugin code should look like below:
Steps to register plugin:
Step 1:
Connect plugin registration tool with your Customer Engagement instance and click on register and register new assembly:
Step 2:
Select the location of your plugin dll and check to select all checkbox and click an ok button at the bottom of the screen:
Step 3:
Once an assembly is registered, your plugins will look like below. Make sure both plugins are visible here.
Step 4:
Right click on the first plugin and click register new step:
Step 5:
Register the pre-operation step as shown below:
Step 6:
Again right click on the 2nd plugin and register the post-operation step as shown below:
Testing:
Step 1: 
We already have a contact in a system with full name Vishal grade as shown below:
Step 2:
Create another contact with the same name as shown below:
Step 3:
Upon creation, the status of contact will automatically change to duplicate as shown below:
Limitation
For a plug-in registered in stage 20 or 40 of plugin execution pipeline, to access the shared variables from a stage 10 registered plug-in that executes on create, update, delete or by a RetrieveExchangeRateRequest, you must access the ParentContext.SharedVariables collection. For all other cases, IPluginExecutionContext.SharedVariables contains the collection. 
What this means is that if the Shared Variable is being set during Pre-Validation, you need to look at the Parent Context to find it when retrieving it in a Pre-Operation or Post-Operation step. It may not be in the immediate Parent Context either; you may need to check each parent’s parent to find where the Shared Variable has been stored.
Lastly, you cannot share variables between steps using different messages and/or entities, even if one triggers the other. For instance, let’s say that we have a plugin that executes when an Account is updated and that this plugin updates associated Contacts. Let’s also say that we have another plugin that gets triggered when the Contact is updated, so we have a case where the Account update plugin triggers this Contact update plugin. You’d see that the IExecutionContext.Depth for the Contact plugin is set to 2, but the Shared Variables you set in the Account plugin will not be available to the Contact plugin.

No comments:

Post a Comment