AX / D365FO – How to Iterate Over Class Contract Attributes in Dynamics 365 FO Using X++

In Dynamics 365 Finance and Operations (D365FO), developers often work with data contracts in the context of the SysOperation framework. Sometimes, you might need to dynamically access all the attributes (properties) of a data contract without manually specifying each one. This article will guide you through a method to iterate over all the attributes of a data contract class and store them in a map, using X++ and .NET reflection.

Introduction

Data contracts in D365FO are classes that define the parameters of a service operation. They are commonly used to pass data between layers in the SysOperation framework. Accessing each attribute manually can be tedious, especially when dealing with contracts that have many properties or when properties might change over time. Using reflection, we can dynamically access all public properties of a data contract.

Prerequisites

  • Familiarity with X++ programming.
  • Basic understanding of the SysOperation framework and data contracts.
  • Access to a D365FO development environment with the necessary permissions to use .NET interop.

Step-by-Step Guide

1. Decorate Your Data Contract Class

Ensure your data contract class is properly decorated with [DataContractAttribute] and its properties with [DataMemberAttribute]. This is essential for serialization and for the properties to be recognized by reflection.

[DataContractAttribute]
public class MyContract
{
    [DataMemberAttribute]
    public str parmAttribute1(str _attribute1 = attribute1)
    {
        attribute1 = _attribute1;
        return attribute1;
    }
    private str attribute1;

    [DataMemberAttribute]
    public int parmAttribute2(int _attribute2 = attribute2)
    {
        attribute2 = _attribute2;
        return attribute2;
    }
    private int attribute2;

    [DataMemberAttribute]
    public date parmAttribute3(date _attribute3 = attribute3)
    {
        attribute3 = _attribute3;
        return attribute3;
    }
    private date attribute3;
}

2. Use .NET Reflection to Access Properties

Utilize the CLR interop capabilities in X++ to access .NET reflection classes. Here’s how you can iterate over the properties:

public void ContractToMap(Object _contract)
{
    Map                                     contractMap = new Map(Types::String, Types::String);
    System.Type                             clrType;
    System.Reflection.PropertyInfo[]        properties;
    System.Reflection.PropertyInfo          property;
    int                                     i;
    str                                     propertyName;
    System.Object                           propertyValue;

    // Get the CLR type of the contract object
    clrType = _contract.GetType();

    // Get all public properties of the contract object
    properties = clrType.GetProperties();

    // Iterate over the properties
    for (i = 0; i < properties.get_Length(); i++)
    {
        property = properties.GetValue(i);

        // Get the name of the property
        propertyName = property.get_Name();

        // Get the value of the property
        propertyValue = property.GetValue(_contract, null);

        // Insert the name and value into the map
        contractMap.insert(propertyName, any2Str(propertyValue));

        // Output for verification
        info(strFmt("Attribute: %1, Value: %2", propertyName, any2Str(propertyValue)));
    }

    // Now, contractMap contains all the attributes and their values
    info(strFmt("The map contains %1 elements.", contractMap.elements()));
}

3. Explanation of the Code

  • System.Type clrType: Retrieves the CLR type of the contract object, which is necessary for reflection.
  • GetProperties(): Retrieves an array of PropertyInfo objects representing all the public properties of the contract.
  • Iterate over properties: The for loop goes through each property in the array.
  • GetValue(): Retrieves the value of each property for the given object.
  • Insert into map: Stores the property name and value in a Map object for later use.
  • any2Str(): Converts the property value to a string, regardless of its original type.

4. Handling Different Data Types

The any2Str() function simplifies the conversion of various data types to a string. If your properties are of complex types or collections, you may need to implement additional logic to handle those types appropriately.

5. Putting It All Together

Create an instance of your contract, set its properties, and call the ContractToMap method:

public static void Main(Args _args)
{
    MyContract myContract = new MyContract();

    // Set values for the contract properties
    myContract.parmAttribute1("Value1");
    myContract.parmAttribute2(123);
    myContract.parmAttribute3(systemDateGet());

    // Call the method to iterate over the contract attributes
    ContractToMap(myContract);
}

Considerations

  • Performance: Reflection can impact performance. Use this approach judiciously, especially in performance-critical applications.
  • Security: Ensure that your environment’s security policies permit the use of reflection and CLR interop.
  • Error Handling: Include try-catch blocks to handle any potential exceptions that may occur during reflection, such as accessing inaccessible properties.

Conclusion

By leveraging .NET reflection within X++, you can dynamically access all the attributes of a data contract without manual enumeration. This method improves flexibility and maintainability, especially when working with contracts that have numerous or frequently changing properties.

References

Leave a comment