You've heard it by now. In Dynamics AX 2012, X++ can actually run in the .NET CLR. What I've often heard is "X++ running on the server runs in IL". Well, that is somewhat true. But it doesn't mean setting your classes or menu items to "RunOn Server" makes them run in IL.
So what runs in the CLR "automatically"? Well, any execution path that starts on the server definitely does. First of all that means, batch jobs... the server runs and executes batch jobs, so they all run as IL. All services run as IL, since they start on the server tier as well. Any "Business Operation" (the RunBase replacement called "Business Operation Framework" - more on that here) also runs as CLR (since it uses the service framework as a back end) So does that mean code started from the AX client never runs as IL, even when it's set to run on the server tier? Well, not automagically. But, we can do some manual magic!
Consider the following method (created on a class I called "XppIL"), it checks whether it is running in the CLR or as interpreted X++ script and outputs an infolog to show you the result. Note it accepts and returns a container. Anyone who has worked with the runAs() method in AX 2009 will recognize this pattern.
Notice the method does not require the "server" modifier (although adding won't harm anything of course). It is just public static, taking basically the default "called from". You can make this "server", but as said earlier, that won't make it run as IL necessarily.
Ok, so how do we now run this as IL? Calling this now from any method (server or client) will just return the "X++ interpreted" message... Well, let's create a Main method on our "XppIL" class and call the static method. But not the old fashioned way, we use the new function "runClassMethodIL". We don't care about passing in or getting out containers, so we'll just pass in a conNull() since we need to pass in something.
To call the runClassMethodIL function, we need to assert the XppILExecutePermission. Also as a good practice we don't use strings for the method and class name, but use the classStr() and staticMethodStr() precompiler functions.
For good measure, we'll also call the method directly, from our Main method that we make run on server, just to make the point "server" doesn't mean IL necessarily.
The last thing we need to do is make sure we generate the CIL so our X++ can run in the CLR. No need to compile the whole thing again, you can do an "incremental" compile to just compile any changes you made since the last CIL generation.
We can run our class now. And, as expected, our output looks as follows.
Great! That worked. But, how do we now debug this? Well, in Visual Studio of course! Few things on that. First, remember the IL runs on the server, so you need to debug the server process. Secondly, to debug the server service, your Visual Studio should run as administrator (elevated permissions). If it's not running as such, Visual Studio will ask you. Let me show you. Open Visual Studio. On the debug menu, select "Attach To Process".
From the list, select the Ax32Serv.exe. If it's not on the list, make sure you have the "Show processes from all users" and "Show processes in all sessions" checked. Click the "Attach" button. If your Visual Studio is not running as administrator, you will get the prompt as shown below. Once you say "restart under different credentials", and then click "yes" to allow it, Visual Studio will restart in administrator mode. You will have to repeat the above steps to attach the debugger to the Ax32Serv.exe.
Next, open the application explorer (View / Application Explorer). Navigate to Classes and find the XppIL class. Expand the class and double-click on the "RunCode" method. This will open the X++ code in Visual Studio (not editable, and unfortunately no code highlighting either).
Let's put a breakpoint in this code. Put your cursor on the line with "if (xSession" and press F9 to put a breakpoint on that line. This will put either a red dot or a red circle in front of the line. If you get a red circle (shown below), you will notice it has a little warning icon in there as well. If you hover your mouse over it, you will notice the tooltip says "The breakpoint will not currently be hit. No symbols have been loaded for this document". Basically this happens because AX will not load all assemblies at startup, but rather load them on first use. So, as soon as we start our class, you will see Visual Studio's output window (if you have that open) show assembly loading, including the IL compiled X++. So, get back into AX and run the class again...
Windows should switch you to Visual Studio and you will see the breakpoint hit there. Notice you have full capability here, including stack trace, variable watches, etc. One MAJOR point to remember here is that Visual Studio supports conditional breakpoints. That's right. The feature you've been waiting for.
As far as debugging in Visual Studio goes, the shortcuts are the same as in AX. F5 is continue, F10 is Step Over, F11, is Step Into, etc.
Have fun in the fast lane!