Tuesday, July 19, 2011

AX 2012 Models & Events Part2: Events

In this 3-part series I will let you in on the power of the 2012 model architecture in combination with events. There is a paradigm shift in regards to customizations and even ISV code that will make life so much easier, provided everyone uses this new model. To that end, I will talk a bit about models, events, and then put it all together and SHOW you the advantage. The originally article kept getting bigger and bigger, so I decided to split it up in three parts, I will publish one every day.

Part 1: Model Architecture
Part 2: Events
Part 3: Full Walkthrough (with code and screenshots)

AX 2012 introduces the concept of events (whitepaper is available on Microsoft's Download Center - for a list of all available 2012 documentation see my June Documentation round-up post). For those of you familiar with C# you will realize that delegates are a great concept, but they require the base functionality to have these delegates (for those unfamiliar, delegates are event "hooks" the application exposes). I counted the number of delegates in the RTM release of AX 2012, and there are about 100 (which is not a lot yet, considering the application has around 5 million lines of code). Chances are your customizations will want to subscribe to places, or make modifications to, code that doesn't provide any delegates. Peter Villadsen and his team thought about this, and introduced a concept of pre and post-handlers. This basically allows you to "subscribe" your code to any method in the application, without having to modify the standard application code to make that call. For the sake of customizations, I will talk about these pre/post handlers, and not delegates. The principles are similar enough. I will have another article on delegates altogether, since there are some interesting details to them.
In any case, pre-post handlers come in two flavors: the "lightweight" handlers, and the other handlers that don't have an official name (yet?). Let's call them original handlers (one could argue they should use some opposite term of lightweight, but let's not go there).
Let's start with the original handlers. They are always static methods (since pre-post handlers can only be attached in the AOT, as opposed to delegate handlers that can be subscribed at runtime), obviously public (remember, new methods in AX 2012 will be explicitly declared "private" by default), and no return type (=void), and accept an object of type XppPrePostArgs.

The XppPrePostArgs object is the juice of the meat. This gives you access to the arguments passed into the method you're subscribing to (using getArg() or args()), the return value being returned from the method you're subscribing to (getReturnValue()), and it has a method getThis() which returns the instance of the object that fired the event. Of course, you can modify the arguments being passed in, and modify the return value of the original method. But here's the thing! Technically, it is not guaranteed in what order the event subscribers will be called. This is because it depends on the order in which code is imported, models are installed, etc. So changing the return value (in post-handlers) or arguments (in pre-handlers) is possible, but since you are not guaranteed to be the last person to touch these values, it is not guaranteed that nobody will overwrite your values.
Since changing the return value cannot be guaranteed, it becomes a little less useful. On top of that, accessing arguments through the args() or getArg() methods is not the safest thing. You either access the arguments through index or through name (ugh), which you won't know works until runtime. Because of these limitations and potential issues, lightweight handlers were invented. They are lightweight in the sense that they do not provide a means to change the arguments (but you can read them - and remember certain types are passed by reference so technically you can change them), no means to change the return value, and no means to retrieve the object instance the event was thrown from. Unfortunately, the latter makes the lightweight handlers handicapped to a certain extent. All in all, depending on your situation, you will find that either one will support you in your endeavors. It's a powerful feature.
To finish the quick introduction (without spoiling the next article), to hook up the subscriber, you either drag your subscriber method and drop it on the method you wish to subscribe to. Or you right-click the method you wish to subscribe to and select "New Event Handler Subscription".

Note that the "subscription" itself (the node in the AOT) carries a name property. Make sure to give this a unique name. Also in the properties, you can denote the subscription to be pre or post, and in case you wish to write the code in managed code, you can, by setting the EventHandlerType property to "Managed". In that case, make sure, for the class name, to include the full assembly name as well (eg: MyCompany.MyProject.MyClass).

There are two major things you need to know to appreciate this pre/post handler feature even more:
  1) The "subscription" (the link between the original method and your subscriber method) has an AOT node, and is stored in the layer/model separate from the original code (so giving it a unique name is of the essence!)
  2) The compilation of the original method will "append" the call to your handler to itself - this means no "lookup" overhead at runtime (if you think about this, it will answer any questions you may have around database transactions, exceptions, etc… consider the pre/post handler as if they were calls to your method at the very beginning, or very end, of the method you're subscribing to).

The key here is number 1 though, the fact that the subscription is stored separate from the original method. This is in fact the number one reason for the power of the events and models combo!

Next: Part 3: Full Walkthrough (with code and screenshots)

No comments:

Post a Comment