One of the great new development improvements for Microsoft Dynamics AX 2012 is "Eventing".
For most people, that have ever done any Object oriented development or programming, eventing is a concept that most familiar.
It is a concept that is used to fire before, just before or just after a given method call takes place. These can also be design within the middle of a method as well, if a given piece of business logic within the middle of a method, make sense to tie an event too.
If you bring this to a more functional level, you can think of eventing as something that happens for a given object. For example, when a Sales Order greater than $10,000.00 is invoiced, an event is fired that automatically places an order for a pizza party, for the dept.
Chances are your customizations will want to subscribe to places, or make modifications to, code that doesn't provide any delegates. Microsoft 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, we will talk about pre/post handlers and delegates.
Now it's very important to point out, that all event handler subscription elements must be static methods. These are the only types allowed, for create such an event handler subscriber, or event listener. 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, 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 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!
However, there is one sore point (in my opinion) in this model: managed code handlers for X++ events do not support complex types!
If events (be it pre/post events or delegate ("coded") events) have complex argument types to their methods (anything that's not a base type), they will not allow managed handlers. On top of that, the Pre/Post handler type using the XppPrePostArgs class as an argument (a complex type) does work with managed handlers. But when subscribing a lightweight handler, or subscribing to a delegate, the managed code handlers CANNOT take complex types.
First, let's create a new class in Dynamics AX 2012 called “MyEvents". We will have a Run method that calls a delegate, we'll need to create that delegate, and a main method to run the class.
To create the delegate, right-click your new class and select New > Delegate, or you can just create a new blank method and type in the method manually as shown below.
There is an abstract "XppEventArgs" class which you can inherit from. I'm using the XppPrePostArgs class (which extends XppEventArgs) to avoid creating a new class for this article. Anyway, next we create a run method which calls the delegate
Finally, we need a Main method to run our class, which will instantiate the class and call Run().
That's all for now, and has we move forward. Try this with some real world example, you will find it very interesting.