Safely Handling AliasedValue in Dynamics 365 Plugins

 Developing plugins for Dynamics 365 often involves extracting and manipulating data from linked entities using FetchXML. One common challenge in this scenario is handling the AliasedValue objects that Dynamics 365 returns when querying attributes from these linked entities.

Developers might encounter errors such as:

Unable to cast object of type 'Microsoft.Xrm.Sdk.AliasedValue' to type 'Microsoft.Xrm.Sdk.Money'.

This error occurs because the data retrieved from a linked entity is encapsulated within an AliasedValue, which needs to be correctly unwrapped to access the actual data.

Understanding AliasedValue

In Dynamics 365, when attributes from linked entities are retrieved through FetchXML, they are returned as AliasedValue instances. This class encapsulates the actual value and provides additional metadata, indicating the origin of the data, which is especially useful in queries involving multiple linked entities.

The Importance of Proper Handling

Directly accessing and casting AliasedValue objects without appropriate checks can lead to runtime errors, particularly type casting errors. These are common pitfalls in Dynamics 365 custom development that can disrupt the functionality of plugins.

A General Approach to Extracting Data from AliasedValue

To robustly handle AliasedValue and safely extract values, a helper method can be highly beneficial. This method ensures type safety and null safety, improving the reliability of your plugins.

Example Method: Safely Extracting Money from AliasedValue

This utility method simplifies the process of retrieving Money values from AliasedValue objects, ensuring type safety and null safety. Below is the implementation tailored for extracting Money:

Code Implementation:

private Money GetMoneyValueFromAliasedValue(Entity entity, string attributeName)
{
    AliasedValue aliasedValue;
    if (entity.Attributes.TryGetValue(attributeName, out object value) && value is AliasedValue)
    {
        aliasedValue = (AliasedValue)value;
        if (aliasedValue.Value is Money moneyValue)
        {
            return moneyValue;
        }
    }
    return null;
}


Call above function when handling the retrieve result.

public class QuoteProductCreate : IPlugin { public void Execute(IServiceProvider serviceProvider) { ... // Fetch all QuoteDetails linked to the same Quote and having Product Bundle string fetchXml = $@" <fetch> <entity name='quotedetail'> <attribute name='quantity' /> <link-entity name='product' from='productid' to='productid' alias='prod'> <attribute name='new_materialcost' /> <attribute name='currentcost' /> <filter> <condition attribute='productstructure' operator='eq' value='3' /> <!-- Product Bundle --> </filter> </link-entity> <filter> <condition attribute='quoteid' operator='eq' value='{quoteRef.Id}' /> </filter> </entity> </fetch>"; EntityCollection results = service.RetrieveMultiple(new FetchExpression(fetchXml)); decimal totalMaterialCost = 0; decimal totalCurrentCost = 0; foreach (Entity detail in results.Entities) { decimal quantity = detail.Contains("quantity") ? detail.GetAttributeValue<decimal>("quantity") : 1; Money materialCost = GetMoneyValueFromAliasedValue(detail, "prod.new_materialcost"); Money currentCost = GetMoneyValueFromAliasedValue(detail, "prod.currentcost"); // Calculate and sum up the weighted costs decimal weightedMaterialCost = materialCost != null ? materialCost.Value * quantity : 0; decimal weightedCurrentCost = currentCost != null ? currentCost.Value * quantity : 0; totalMaterialCost += weightedMaterialCost; totalCurrentCost += weightedCurrentCost; } ... } }

How It Works:

  1. Safe Retrieval: Uses TryGetValue to safely attempt retrieval of the attribute from the entity’s attributes collection, avoiding exceptions if the attribute is absent.
  2. Type Checking: First ensures the retrieved value is an AliasedValue, then checks if the wrapped value is Money.
  3. Null Safety: Returns null if the attribute is not present or not the expected type, allowing the calling code to handle the absence of data gracefully.

Benefits of Using This Method:

  • Robustness: Prevents your plugin from crashing due to incorrect type casts.
  • Clarity: Simplifies the main business logic of your plugin by abstracting the complexity of type checking and null checking.
  • Reusability: Can be reused across multiple plugins that require similar data handling for linked entity attributes.

This method is particularly useful in complex Dynamics 365 plugins where multiple linked entities are involved, ensuring that your code remains clean, maintainable, and error-free.

No comments:

Post a Comment