Talk in Prague – Dynamics Technical Conference: Direction of AX

I apologize, but if you’re unfortunately enough not to speak Czech and not to live near to Prague, you probably can stop reading. Hopefully you’ll find something more useful here next time.

Others please note that I’m giving a talk about Dynamics AX in Prague on Tuesday, 24 February 2015.

On the beginning on February, another Microsoft Dynamics Technical Conference took place in Seattle, this time with more than 120 session about Dynamics AX and Dynamics CRM. In Prague, I would like to share some interesting information from this conference (e.g. about AX 7 and Lifecycle Services) and try to sketch what impact will the forthcoming changes have on usage and development of Dynamics AX in future.

The event is being held in the private room of pizzeria Kmotra, from 16:30. After the more official part, we’ll continue with informal discussion about Dynamics AX and anything related.

If you’re going to attend, please register here. Information about approximate number of attendees will help me to prepare the event. Thank you in advance.

Custom date and time format

I was extending a customization of Dynamics AX when I ran into the following piece of code. It formats the current date and time to something like 20150525_0042.

str dateValue, dateFormat;
dateValue   = date2str( systemDateGet(),
dateFormat = strFmt(    "%1%2%3",
                        dateValue, '_',
                        subStr( strRem(time2Str(timeNow(), TimeSeparator::Space, TimeFormat::Auto), ' '),

If I haven’t formatted the code to make it more readable, you would struggle to follow what it does. Even the original developer had the same problem – I already fixed two bugs (!) in this code snippet.

I rather dropped the code completely and replaced it with this:

str formatted = System.String::Format(
                                DateTimeUtil::newDateTime(systemDateGet(), timeNow()));

Better, isn’t it? It’s not only shorter, more importantly it’s much easier to understand and maintain. It would be even simpler if I used DateTimeUtil::utcNow() instead of keeping the original logic with systemDateGet() and timeNow().

This is just a simple example of how .NET Interop from X++ can make your life easier – the amount of .NET code available for you is huge. In this particular case, I called String.Format() method with a custom date and time format. You can also use custom formats when parsing strings to dates (DateTime.ParseExact()), which is probably even more useful.

Customer Experience Improvement Program dialog

If you create a script that runs AX client, e.g. to compile CIL, you might find that it gets stuck immediately after starting AX. It’s typically because your build user is asked to join the Customer Experience Improvement Program. One option is to log as the build user and choose yes or no. But if the account doesn’t have permissions for interactive login, or you simply look for an easier way, you can set it directly in SysUserInfo.SqmEnabled field.

I remembered this problem, but I couldn’t remember at all where the options is saved. From now, I can always find it here. :)

Test Data Transfer Tool: Getting errors from log

I imported data to AX with the Test Data Transfer Tool and it told me that some errors occured. The log file is quite large, so I asked myself what’s the easiest way to find these errors. This is my approach, using a very simple Powershell script:

[xml]$dplog = Get-Content C:\Windows\System32\dplog.xml
$dplog.root.item | ? Status -eq "Failed"

Note that this is for Powershell 3; you would have to change it to something like this if you still use Powershell 2:

[xml]$dplog = Get-Content C:\Windows\System32\dplog.xml
$dplog.root.item | ? {$_.Status -eq "Failed"}

This is how the output looked like in my case:

status      : Failed
message     : One or more indexes were disabled on table TableXYZ to allow the data to import.
              Use the following SQL to enable the indexes once you've fixed the data:
                  ALTER INDEX ALL ON [TableXYZ] REBUILD
              The original index violation message is:
              Cannot insert duplicate key row in object 'dbo.TableXYZ' with unique index
              'I_104274XYZIDX'. The duplicate key value is (5637144576, 196, , ).
              The statement has been terminated.
direction   : Import
action      : Overwrite
database    : TestAX
table       : TableXYZ
targetTable : TableXYZ
folder      : C:\TestData

Tips for CIL debugging: Collection classes

In some cases, you can make your debugging much easier if you debug CIL instead of the original X++ code. Working with collection classes (lists, maps, etc) is such a case.

For example, the following picture shows a map (mapping customer IDs to CustTable records, e.g. for caching) as displayed by the AX debugger:


If you do the same thing in CIL / Visual Studio debugger, it looks almost the same:


But there is one huge difference – unlike in AX, you can actually open the content of the collection. You can easily see the number of elements and you can open any of them and see the full object graph (such as fields of CustTable records, in our case).


The inability to see the content of collections in AX debugger can be quite annoying. You can’t simply see what’s inside; you need some code that explicitly iterates the collection. Debugging the CIL code instead of X++ can be much easier.

By the way, you can dig into many other things that looks atomic in X++. For example, utcdatetime is a primitive type in X++, but it’s a struct in CIL and you can see many properties unavailable in X++: