Back
Featured image of post Utilising Pre/Post Entity Images in a Dynamics CRM Plugin

Utilising Pre/Post Entity Images in a Dynamics CRM Plugin

One of the challenges when first working with CRM Plugins is understanding how the execution context works. To briefly summarise, this contains the information relating to how and when the plugin is executed. It can give you answers to some of the questions you may wish to “ask” your CRM - for example, what record has triggered this plugin? Which CRM User forced the plugin to execute? You may also assume that the context will contain all of the fields of that entity that you can then access. This is not always the case - typically, as part of an Update request, only the fields that triggered the update will be made available. Or consider an Associate/Disassociate request (i.e. when someone relates/unrelates two records in CRM). As part of a one-to-many (1:N) relationship, only one field has changed; so that is the only field that is contained within the execution context.

The above being the case, what options do you have if you need to access fields that are not included in the context? You have two choices available to you:

  1. Obtain a reference to Organisation Service within your plugin, and then use a Retrieve request to return the fields you need from the plugin. As the context will always contain the GUID for the record that has changed, this is generally the most common way you will see this done.
  2. Utilise either a Pre or Post Entity Image of the record, which contains the attributes that you need to access.

In the past, I would always end up going down the first route. Recently though, I have been evaluating Entity Images more and more, and have begun to actively use them as part of my plugins. Entity Images are, essentially, snapshots of the CRM record that are stored on the platform either before the database operation has completed or straight after - you can decide which one you want to use, depending on what your plugin is doing. They are configured as part of deploying your plugin to your target CRM instance, and the steps involved are actually quite simple - I think its generally the case that they are not well-understood or utilised by developers who are learning about CRM for the first time.

So why should you go to the extra effort to use them within your plugins?

As alluded to above, using Pre Entity Images means you can get a snapshot of your CRM data before the data was changed. This may prove to be particularly invaluable in cases where you need to perform a before/after comparison on a particular field, and then execute a specific action either way. The only non-entity image way of doing this within CRM would be via hidden field that stores the current value of your field in question, which is referenced and updated once your business logic has completed. A slightly in-elegant solution, and one that is questionable, given that we can utilise Entity Images instead. Having ready access to the attributes which may not necessarily be exposed to the plugin when it is executed is particularly invaluable, given that this avoids a scenario where you would have to go down option 1). Disadvantages of this approach is the potential for unnecessary delays in your plugin completing and problems with your CRM instance as a whole, if your CRM’s web services are already accessed to breaking point.

There must be a catch, surely…

On the whole, it doesn’t look like it, but you do need to aware of a few things. As you may have already guessed, if your plugin runs on the Create message, you won’t be able to access any pre-image of the record; likewise, for Delete message plugins, the post-image will not be available. It should be fairly obvious why this is the case. You are also restricted with the number of Messages that support Pre/Post Images. The full list can be found here, but to summarise the most important Message types, only Update, Assign, SetState & Merge support both Image types. Bear in mind too the additional “gotchas”, which this article touches upon. If in doubt, then boot up your sandbox CRM environment and cry havoc with your test code.

Lets take a closer look at how Pre and Post Images can be implemented as part of a CRM Plugin…

The below example will compare the Pre and Post Image values of the Lead Company Name field and, if they have changed, send an email message to a Sales Manager user to alert them of this fact. Be sure to add references to the Microsoft.Xrm.Sdk and Microsoft.Crm.Sdk.Proxy .dlls from the SDK:

//Extract the tracing service for use in debugging sandboxed plug-ins.

ITracingService tracingService = localContext.TracingService;
tracingService.Trace("Implemented tracing service succesfully!");

// Obtain the execution context from the service provider.
IPluginExecutionContext context = localContext.PluginExecutionContext;

// Get a reference to the Organization service.
IOrganizationService service = localContext.OrganizationService;

if (context.InputParameters.Contains("Target"))
{
  //Confirm that Target is actually an Entity
  if (context.InputParameters["Target"] is Entity)
  {
    Guid _userID = context.InitiatingUserId;
    
    //Retrieve the name of the user (used later)
    Entity user = service.Retrieve("systemuser", _userID, new ColumnSet("fullname"));
    
    string userName = user.GetAttributeValue<string>("fullname");
    
    Entity lead = (Entity)context.InputParameters["Target"];
    
    Entity preLead = (Entity)context.PreEntityImages["Image"];
    
    Entity postLead = (Entity)context.PostEntityImages["Image"];
    
    string preCompanyName = preLead.GetAttributeValue<string>("companyname");
    
    string postCompanyName = postLead.GetAttributeValue<string>("companyname");
    
    tracingService.Trace("Pre-Company Name: " + preCompanyName + " Post-Company Name: " + postCompanyName);
    
    if (preCompanyName != postCompanyName)
    {
      tracingService.Trace("Pre-Company Name does not match Post-Company Name, alerting sales manager...");
      
      //Queue ID for our Sales Manager
      Guid _salesManagerQueueID = new Guid("41b22ba9-c866-e611-80c9-00155d02dd0d");
      
      Entity fromParty = new Entity("activityparty");
      Entity toParty = new Entity("activityparty");
      
      //Email body text is in HTML
      string emailBody = "<html lang='en'><head><meta charset='UTF-8'></head><body><p>Hello,</p><p>Please be advised that I have just changed the Company Name of a Lead record in CRM:</p><p>Lead Record URL:  <a href='http://mycrm/MyCrmInstance/main.aspx?etn=lead&pagetype=entityrecord&id=%7B" + lead.Id + "%7D'>" + postCompanyName + "</a></p><p>Old Company Name Value: " + preCompanyName + "</p><p>New Company Name Value: " + postCompanyName + "</p><p>Kind Regards</p><p>" + userName + "</p></body></html>";
      
      fromParty["partyid"] = new EntityReference("systemuser", _userID);
      toParty["partyid"] = new EntityReference("queue", _salesManagerQueueID);
      
      Entity email = new Entity("email");
      
      email["from"] = new Entity[] { fromParty };
      email["to"] = new Entity[] { toParty };
      email["subject"] = "Lead Company Name Changed";
      email["directioncode"] = true;
      email["description"] = emailBody;
      
      //This bit just creates the e-mail record and gives us the GUID for the new record...
      Guid _emailID = service.Create(email);
      
      tracingService.Trace("Email record " + _emailID + " succesfully created.");
      
      //...to actually send it, we need to use SendEmailRequest & SendEmailResponse, using the _emailID to reference the record
      SendEmailRequest sendEmailreq = new SendEmailRequest
      {
        EmailId = _emailID,
        TrackingToken = "",
        IssueSend = true
      };
      
      SendEmailResponse sendEmailResp = (SendEmailResponse)service.Execute(sendEmailreq);
      
      tracingService.Trace("Email record " + _emailID + " queued succesfully.");
      }
    else
    {
      tracingService.Trace("Company Name does not appear to have changed, is this correct?");
      return;
    }
    tracingService.Trace("Ending plugin execution.");
  }
}

Once we have written our code and built our solution, we deploy our plugin in the normal way via the Plugin Registration Tool - ensuring that we configure our step to fire on the correct message:

Next, we need to configure our Pre/Post Images manually. Just because we have referenced them in our code above doesn’t mean they will automatically become available to us as our plugin is executed. Fortunately, adding them on is not too difficult and we can do it directly within the Plugin Registration Tool. First, highlight our new plugin step and select Register New Image:

One good thing about this is that we can configure both our Pre and Post Images in the one screen. We just confirm that our intended plugin step is selected, tick both of the boxes and ensure that the following details are completed:

  • Name: Specify a name for this image. This can be anything you want it to be, but I would recommend using the same value as Entity Alias
  • Entity Alias: This is the name that is used in our code above to reference the image. This must match exactly against this in order for the code to work correctly.
  • Parameters: Here you specify which attributes will be made available within the image. By default, all attributes are included, but you should specify only the attributes you need to work with in your plugin. For our example plugin, we only need the Company Name field, so this is the only attribute we will select.

Your settings should look something like the below:

With everything setup, we can now test our plugin. In this case, I have changed one of the sample data leads to force the plugin to execute:

We can then see that our Email record is successfully created, which is able to reference the value of the Company Name field before the change:

Playing back the plugin within Visual Studio demonstrates that our Pre and Post images are Entity objects, meaning that we can interact with them the usual way - nothing new to learn or master, which is good 🙂

Conclusions - or Wot I Think

Like most things with CRM, Entity Images have a time and place. If you have a desire to query additional data concerning record relationship attributes etc. as part of your plugin, then a Retrieve request is still going to be the only way you can accomplish this. There is also some additional administrative head-room required when working with Images - if, for example, you forget to specify your Pre & Post Images when deploying your plugin, then you are going to encounter immediate problems within your CRM. Having said that, I think there is an excellent case to be made to using Entity Images as much as feasibly possible in your code. A Retrieve request on a particular busy CRM platform just to return one attribute value could store up problems for your CRM instance in the long-haul; having this one value stored as part of an entity Image seems a much more sensible and logical approach. I am further struck by how useful entity images can be if you need to reference data changes before and after a record change - going back to our example above, where we would instead look at creating custom field within CRM to store this value, having it made available as part of an Entity Image could score a major time saving. Finally, you are not just restricted to using the one Pre/Post Image - you can setup multiple ones that contain different fields from your entity, that are accessed in different parts of your code, depending on your logic. I think developers working with CRM definitely owe it to themselves to check out Entity Images at least once - I think they will be pleasantly surprised at their capabilities and, one would hope, the increased performance of their CRM instance as a consequence of using them!

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy