Tuesday, April 5, 2016

A bit more about SDK “Merge” message in CRM plugins

One of our clients is using auto numbering on contact records. A few days ago, they reported to have duplicates in the system. So I started the investigation, I could not believe that this could happen in our solution. But what I had found out was that those duplicates were generated as a part of the "Merge" functionality available in CRM. Every time users "Merge" the customer and choose the subordinate's customer number to come across, it will override the master record's customer number with the subordinate record's number.

So we decided to write a plugin that will stop the users from overriding the master record's customer number.
The  context.InputParameters  collection of the merge message contains 3 of the following objects
  1. Target ( entity reference of the master record)
  2. SubordinateId ( guid of the subordinate record)
  3. UpdateContent ( temporary entity that contains the attribute that will be passed to the master record).

The following example does not use the SubordinateId object. We are only using Target and UpdateContent entity. Like any other plugin entity, the "UpdateContent" entity only contains attributes that will be updated in the master record.
Code
 protected void ExecutePreCustomerMerge(LocalPluginContext localContext)  
  {  
       if (localContext == null)  
       {  
         throw new ArgumentNullException("localContext");  
       }  
       IPluginExecutionContext context = localContext.PluginExecutionContext;  
       ITracingService trace = localContext.TracingService;  
       IOrganizationService service = localContext.OrganizationService;  
       // if the sdk message is merge  
       if (context.MessageName.Equals("merge", StringComparison.InvariantCultureIgnoreCase))  
       {  
         //get the merged entity  
         Entity updateContentData = context.InputParameters["UpdateContent"] as Entity;  
         //if the merged record is null then do nothing  
         if (updateContentData == null) { return; }  
           //get the customer number of merged record  
           string mergedCustNumber = updateContentData.GetAttributeValue<string>("custNumber");  
           if (mergedCustNumber == null) return;  
           else  
           {  
             // if the merged CustNumber is not null retrieve the CustNumber of the master record to display in the message  
             // get the master entity reference  
             EntityReference targetReference = (EntityReference)context.InputParameters["Target"];  
             //trace.Trace("entity reference " + targetReference.LogicalName.ToString());  
             //retrieve the CustNumber number of the master entity  
             Entity target = service.Retrieve(targetReference.LogicalName, targetReference.Id, new ColumnSet("custNumber"));  
             string masterCustNumber = target.GetAttributeValue<string>("custNumber");  
             throw new InvalidPluginExecutionException("You cannot update the CustNumber of the Master record. Master CustNumber :" + masterCustNumber + " and New CustNumber :" + mergedCustNumber);  
           }  
         }  
  }  

Some Other Observations
When I tested this plugin in CRM2013 roll up 2, I did not receive the message thrown using InvalidPuginExecutionException. Instead, I received the following message:
I think it is a bug in CRM2013, that is now fixed in CRM2013 SP1.

When I tested the same plugin on CRM2013 SP1 UR3, It displays the proper message, as thrown by the InvalidPuginExecutionException.




6 comments:

  1. Great blog Amreek. Very informative.

    I have 2 questions... Do we have access to preimage in this plugin message. If yes would it point to the Target or the Subordinate. I assume it will be the Target and based on that it might eliminate the need for the second Web service call to retrieve the masterCustNum from the target.

    Second question: if I remove the custNum from the UpdateContent record, would it not override the master number? I'm thinking about rather than I display an error, I'd allow the process to go through but the plugin will prevent the master number from being overridden.

    I'm asking these because I'll need to implement this functionality. Thanks to your code, will make my life easier.

    ReplyDelete
  2. According to the Microsoft documentation, pre and post images are available for both target and subordinate records. I have not tried myself yet.
    https://msdn.microsoft.com/en-au/library/gg309673.aspx

    Second question:Yes you are correct. According to my requirements, I have to display the error message.The CRM customers in my scenario also have external portal access. The user may need to make the changes to the existing records before merging them.

    ReplyDelete
    Replies
    1. Thanks for the response. The sdk article really helped. Cheers.

      Delete
    2. This comment has been removed by the author.

      Delete
  3. 2 years later and this is still a great post. I have one question. Did you create a pre- or post step to trigger the plugin? I've been trying pre-operation, but the Target is null.

    ReplyDelete
  4. Have you ever considered about adding a little bit more than just your articles?
    the app developers

    ReplyDelete