Thursday, September 1, 2016

Dynamics AX 7 - Extensions - Part I

The new Dynamics AX (AX 7) attempts to minimize overlayering (“customization”) and promote extensions, which allow adding functionality without modifying the source code of the original object. For example, you now can attach a field to a table without changing the definition of the table itself. It has many benefits – no changes in existing objects mean no code conflicts and much easier upgrades, it’s not necessary to recompile the original object and so on.
AX 7 RTW introduced extension methods. Extension methods are static methods defined in a completely different class, yet they can be called in the same way as if they were instance methods of the “extended” class, table or so.
Update 1 added something called class extensions, which allows adding not only methods but also class variables, both instance and static, constructors and static methods.
For example, the following piece of code augments the standard Dialog class with a variable and methods working with the variable:
[ExtensionOf(classStr(Dialog))]
final class MyDialog_Extension
{
    private int x;
 
    public void setX(int _x)
    {
        x = _x;
    }
 
    public int getX()
    {
        return x;
    }
}
You can use these methods directly on the Dialog class:
Dialog d = new Dialog();
d.setX(50);  
int x = d.getX();
As you would expect, the value set by setX() is stored in the variable and you can retrieve it by calling getX().
But how does it really work? How Dialog class knows about these new methods and where is the value actually stored, if it’s all defined in a completely different class?
You might think that MyDialog_Extension inherits from Dialog and replaces the Dialog class, it’s a partial class or something like that, but it’s not the case.
The methods are actually extension methods as we know them from AX 7 RTW. Don’t get confused by the fact that we declare them as instance methods; they’re converted to normal static extension methods under the hood. For example:
// This instance method in the extension class…
public void setX(int _x) {}
 
// …is converted to a static extension method like this:
public static void setX(Dialog _dialog, int _x) {}
// As usual, the first argument is object to which the extension methods applies.
The conversion happens when X++ is compiled to CIL and you normally don’t have to bother about it; I’m mentioning it to demonstrate that it’s really just a normal extension method.
Generating different CIL than what you see in X++ might look weird, but it’s a common way to extend CLI (“.NET”) languages without changing the Common Language Runtime (CLR). For example, if you use the async keyword in C#, C# compiler uses standard CLR constructs to generate a whole state machine that handles asynchronous processing. Because CLR receives normal CIL code, it doesn’t need to know anything about X++ class extensions nor C# async/await.
All right, so methods in class extensions are just common extension methods, which explains how methods are “attached” to the augmented class. But where AX stores the variables? How can static methods of the extension class access instance variables?
Again, the solution isn’t too complicated. Under the hood, the extension class has a static variable which maintains references between instances of the augmented class and instances of the extension class. In my case, it maps instances of Dialog and MyDialog_Extension.
When I call a method of my MyDialog_Extension, it gets a Dialog instance as the first argument. It looks into the static map, obtains the corresponding MyDialog_Extension instance (it might have to create it first if it doesn’t yet exist) and then it accesses its fields.
The following code is a simplified demonstration of how it works.
// A demonstration - not the real implementation
final class MyDialog_Extension
{
    private int x;
    private static Map mapDialogToExtension;
 
    public static void setX(Dialog _dialog, int _x)
    {
        MyDialog_Extension extension = mapDialogToExtension.lookup(_dialog);
        if (!extension)
        {
            extension = new MyDialog_Extension();
            mapDialogToExtension.insert(dialog, extension);
        }
        // Here we're accessing the instance variable
        extension.x = _x;
    }
}
Now it’s clear that extension classes don’t modify their augmented classes in any way. All variables declared in an extension class are stored in its instances – it’s rather similar to joining two separate tables.
Because extension classes merely get instances of augmented classes by references, they can’t access its internal state or call private methods.
You can also attach static methods and class fields (variables and constants).
Using static methods in class extensions is useful because it’s easier to find static methods on the corresponding class rather in some utility classes. It also allows you to add methods to the Global class and call them without specifying any class name.
Using static fields can also be very useful. The following example shows adding a new operator (implemented as a public constant) to DimensionCriteriaOperators class.
[ExtensionOf(classStr(DimensionCriteriaOperators))]
final static class MyDimOperators_Extension
{        
    public const str MyNewOperator = '!';
}
As with methods, the new constant seems to be a part of the augmented class, although it’s declared somewhere else.
ExtensionPublicConst
In some cases, such a static class with public constants can be a natural replacement of extensible enums.
If you use a static method or a static variable, CIL generated by X++ compiler directly refers to the extension class.  For example, DimensionCriteriaOperators::MyNewOperator is translated to exactly the same CIL code as MyDimOperators_Extension::MyNewOperator. The fact that X++ presents it in a different way is purely for developers’ convenience.
As you see, class extensions are really an evolution of extension methods. Instance methods in class extensions are based on extension methods; they “merely” add an option to work with instance variables. And there a few other useful features, namely constructors and static members.
The main purpose of class extensions is to help with getting rid of overlayering, but that’s not the only use. They have the potential to change how we traditionally design certain things in AX, especially if somebody comes with a common framework based on extensions, as LINQ revolutionized how we work with collections in C#.
For example, are you aware of that you can write extension methods working with all table buffers by extending Common? Like this:
[ExtensionOf(tableStr(Common))]
final class Common_Extension
{
    public List getSelectedRecords()
    {
        List selectedRecs = new List(Types::Record);
 
        if (this.isFormDataSource())
        {
            MultiSelectionHelper helper = MultiSelectionHelper::construct();
            helper.parmDatasource(this.dataSource());
 
            Common rec = helper.getFirst();
            while (rec)
            {
                selectedRecs.addEnd(rec);
                rec = helper.getNext();
            }
        }
        return selectedRecs;
    }
}
The possibilities are unlimited.
That's all for today.
See you around.

Wednesday, July 6, 2016

AX7. "Hacking" the private/protected overlayering issue.

All class member variables are protected by default in AX 7, so it is impossible to access them from extensions. It becomes a real problem when you try to extend classes like SalesLineType.
For example, we want to add custom logic on sales line insert event. Call to super() is commented out so we cannot create pre or post event handlers. We may try to create event handlers for SalesLineType.insert() method, but we won’t get access to salesLine buffer because this variable is protected.
There are two options: use overlaying or use reflection.
Overlaying is the preferable approach, but today we will talk about reflection to explain this option.
Reflection is usually used for unit testing in case you need to cover protected or private code and it is hard to call this code using public API.
It has bunch of disadvantages:
  • It breaches entire basis of OO programming.
  • Slow performance.
  • Possible issues with future updates. Private methods could be changed at any time.
However, once you may get into a situation where it could be еру only option so it’s better to know about this possibility.
Let’s try to change some fields on sales line insert using reflection.
Create new event handler class for SalesLineType and subscribe to post insert:
using System.Reflection;

/// 
/// Handles events raised by SalesLineTypeEventHandler class.
/// 
public class SalesLineTypeEventHandler
{
    [PostHandlerFor(classStr(SalesLineType), methodStr(SalesLineType, insert))]
    public static void SalesLineType_Post_insert(XppPrePostArgs _args)
    {
        SalesLineType salesLineType = _args.getThis();

        var bindFlags = BindingFlags::Instance | BindingFlags::NonPublic;

        var field = salesLineType.GetType().GetField("salesLine", bindFlags);

        SalesLine salesLine = field.GetValue(salesLineType);

        if (salesLine)
        {
            salesLine.MyNewField = 42;
            salesLine.doUpdate();
        }
    }
}
Also, we can call private or protected method:
var bindFlags = BindingFlags::Instance | BindingFlags::NonPublic;

var methodInfo = salesLineType.GetType().GetMethod(methodStr(SalesLineType, checkQuantityUpdate), bindFlags);

if (methodInfo)
{
    methodInfo.Invoke(salesLineType,  new System.Object[0]());
}
You can read more about reflection on MSDN
I still don't think we should rely on that. Sometimes a very small overlayering will bring more good than harm.
That's it. See you guys around.

Wednesday, May 4, 2016

AX7 - Code running on timer.

In previous versions of AX, we could use setTimeOut() method to execute a form method periodically (actually this method belongs to Object, so any class derived from Object could benefit from it). However, this method is deprecated in AX 7 and new setTimeoutEx() is introduced to replace it.
You may find setTimeOut() in source code, but it does nothing, and probably should cause BP error or warning.
I created a sample form to demonstrate how it works. It has only one Time control that is updated each 500 milliseconds. This form is quite similar to AX 2012 tutorial_Timer but it does not exist in AX 7 anymore.
TestTimerForm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Form]
public class TestTimer extends FormRun
{
    void run()
    {
        super();
        element.setTimeoutEx(formMethodStr(TestTimer, updateTime), conNull(), 500);
    }
 
    public void updateTime(AsyncTaskResult _result)
    {
        if (!element.closed()) //otherwise will be executed even after form close.
        {
            TimeControl.value(DateTimeUtil::getTimeNow(DateTimeUtil::getUserPreferredTimeZone()));
            element.setTimeoutEx(formMethodStr(TestTimer, updateTime), conNull(), 500);
        }
    }
}
When you call setTimeoutEx() method AX adds TimerControl control to a form and executes task asynchronously.
Please note two important things here:
  1. Method called by setTimeoutEx() should accept AsyncTaskResult as a parameter or run time exception will be thrown.
  2. updateTime() method checks if a form is not closed, otherwise AX will execute this code even after the form is closed.

That's it. the replacement for its 2012 version.

Thanks.