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:
- Attempt to get the attribute value from the primary entity
- If the primary entity contains the attribute, use its value
- Otherwise, if the primary entity doesn't contain the attribute, attempt to get the attribute from the pre-event image entity
- If the pre-event image entity contains the attribute, use its value
- Otherwise, use some default value (or null)
First, let's take a look at how this logic is often implemented in code.
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.
{
///<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.
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