Dynamics CRM in the Field

Information from the Microsoft Dynamics CRM PFE team working in the field

Code Review: Refactored Handling of Plug-in Pre-Image Attribute Values

Code Review: Refactored Handling of Plug-in Pre-Image Attribute Values

Rate This
  • Comments 6

During a recent Dynamics CRM 2011 code review engagement, I noticed a pattern being implemented repeatedly throughout the customer's plug-in library. This library was in desperate need of a refactor in the form of a method that encapsulated the repeated pattern. In my assessment report, I provided them a suggested method refactor which could eliminated hundreds of lines of redundant plug-in code. Keep reading and I'll provide you this same method to put in your coding arsenal.

The pattern I identified sought to incorporate the values from pre-event entity image snapshots when evaluating the primary entity's attribute values. We most often see this scenario for pre-event Update message plug-in code. The need for such a pattern is dictated by the nature of the Update message where the entity submitted only contains the attributes to be updated. Makes perfect sense…until you are executing within the event pipeline and need to evaluate a condition based on another attribute of the entity that may or may not have been submitted with the update.

Enter pre (and post) event image registrations. Event images provide a snapshot of the primary entity prior to (or after) the requested operation. This capability allows you to have broader context about the entity state without having to incur unnecessary retrieval of the primary entity from within your plug-in operation. Nevertheless, having this additional context means that you have two potential sources for the value of an entity attribute. Handling this unique situation requires additional logic to determine the appropriate value. The logic goes something like this:

  1. Attempt to get the attribute value from the primary entity
  2. If the primary entity contains the attribute, use its value
  3. Otherwise, if the primary entity doesn't contain the attribute, attempt to get the attribute from the pre-event image entity
  4. If the pre-event image entity contains the attribute, use its value
  5. Otherwise, use some default value (or null)

First, let's take a look at how this logic is often implemented in code.

Common Scenario
int value = -1; //default value

if (entity.Contains("attributename"))
{
  value = entity.GetAttributeValue<int>("attributename");
}
elseif (preImage.Contains("attributename"))
{
  value = preImage.GetAttributeValue<int>("attributename");
}

Next, we'll take the logic implemented above and encapsulate it in a method. I chose an extension method in this case to provide fluent companion to the standard Entity.GetAttributeValue<T>(string attributeLogicalName) method.

Extension Method
public static class EntityExtensions
{
  ///<summary>
  /// Extension method to get an attribute value from the entity
  /// or its image snapshot
  ///</summary>
  ///<typeparam name="T">The attribute type</typeparam>
  ///<param name="entity">The primary entity</param>
  ///<param name="attributeLogicalName">Logical name of the attribute</param>
  ///<param name="image">Image (pre/post) of the primary entity</param>
  ///<returns>The attribute value of type T</returns>
  ///<remarks>If neither entity contains the attribute, returns default(T)</remarks>
  public static T GetAttributeValue<T>(this Entity entity,
                                       string attributeLogicalName,
                                       Entity image)
  {
   return entity.GetAttributeValue<T>(attributeLogicalName, image, default(T));
  }

  ///<summary>
  ///Extension method to get an attribute value from the entity or image
  ///</summary>
  ///<typeparam name="T">The attribute type</typeparam>
  ///<param name="entity">The primary entity</param>
  ///<param name="attributeLogicalName">Logical name of the attribute</param>
  ///<param name="image">Image (pre/post) of the primary entity</param>
  ///<param name="defaultValue">The default value to use</param>
  ///<returns>The attribute value of type T</returns>
  public static T GetAttributeValue<T>(this Entity entity,
                                       string attributeLogicalName,
                                       Entity image,
                                       T defaultValue)
  {
      return entity.Contains(attributeLogicalName)
          ? entity.GetAttributeValue<T>(attributeLogicalName)
          : image != null && image.Contains(attributeLogicalName)
              ? image.GetAttributeValue<T>(attributeLogicalName)
              : defaultValue;
  }
}

How does incorporating our new extension method impact the original code? As shown below, each instance of executing this logic has been reduced to a single line of code. Implement this logic even a few times in a single plug-in and the reductions add up quickly.

Refactored Scenario
int value = entity.GetAttributeValue<int>("attributename", preImage, -1);

Remember, if logic is worth repeating, it’s worth implementing once as a method!

Curious what’s involved in the PFE Dynamics Code Review service?  It’s comprised of a thorough analysis of managed, .NET code from components that interact with Dynamics CRM and extend the core platform as well as client extensions such as JavaScript libraries.  That analysis seeks to identify contraventions to known best-practices that present design, security, performance, or maintainability/supportability concerns.  In addition, we commonly provide sample code to demonstrate a remediation approach to the most impactful issues.

Please let us know if the timing is right to explore a Code Review service engagement for your CRM solution or if you’re interested in becoming a Microsoft Premier Services customer.

Austin Jones

Microsoft Premier Field Engineer

  • For me as a newcomer this would a good article to learn. Thanks.

  • Clever! Nice article!

  • It was a nice article any good response from every one. Instead if 4 to 5 lines we can check the attribute is exists or not by using extension method.

      I have a question. Why it is not providing the entire form values instead of the changing attribute.

    Regards

    RAju...!

  • Raju, it only provides the changed attributes for each target to reduce the message size and it reduces certain data conflicts (there's really no need to pass that data anyhow).  And this is exactly why the plugin images exist - to allow you as the developer to take control and keep the right data coming into your plugin no matter what data was changed (if needed). Also keep in mind you can set the ForceSubmit for fields on the form if you need the value to be submitted down from the form every time (versus every single time the platform message is fired no matter where the source is).

    Let us know if you have any more questions on this.  Thanks!

    Sean

  • looks like CRM online doesnt like T

  • @qq - Can you clarify what you're experiencing?

Page 1 of 1 (6 items)
Leave a Comment
  • Please add 2 and 4 and type the answer here:
  • Post