In Dynamics AX, it is not possible to change the user group permissions for admin group. This is because users in this group should always have full control over the Dynamics AX setup.
But sometime, you’ll have to change it, whatever you reason may be. One reason why you might need to change these, is because the user group permissions setup has been messed up by adding one or more new security keys, or by importing them from an xpo file. The security keys will be set to ‘No access’, and because you can’t change these for the admin group, this poses a problem.
This can easily be solved by changing the method isAdmin() on the form SysUserGroupSecurity to return false.
Alternatively, if you don’t want to change your code, you can put a breakpoint on the ‘return true’ statement, and then drag/drop the pointer to return false.
A colleague came up to me today with a problem. She was trying to import an xpo file, and when she ticked the check box ‘Show details’ in order to compare the objects in the xpo file, the Dynamics AX client crashed. No message was shown, the application just quit. It was also impossible to reconnect to the Application Object Server because the AOS had crashed as well. When you restarted the AOS, you could easily reproduce this scenario by repeating the above steps.
Sometimes, the following message was logged in the event log on the client, basically informing you that the AX client had crashed:
Faulting application ax32.exe, version 5.0.1000.52, stamp 490c41fb, faulting module unknown, version 0.0.0.0, stamp 00000000, debug? 0, fault address 0x0bbf0b3c.
In the event log on the server an other message was logged, but not every time the AOS crashed:
Object Server 16: RPC error: Client provided an invalid session ID 3
From what I understand, this message is logged when a client sends an RPC request to a server that has ended the session for this client, which would be the case if the AOS crashed.
Once again, the event log is pretty useless. The real problem lies in the application files, more specifically the Microsoft Dynamics AX Label Index files. These are the files that have the extension .ali. For some reason, one or more of these index files are corrupt, and this causes the import process to fail, and the AOS to crash. At the time, the AOS server was low on diskspace, and that could be the cause of the corrupt index files. Luckily, index files such as ali files can be deleted when the AOS is down, and will be rebuilt when the AOS is started.
After all label index files were deleted, and the AOS restarted, the xpo could be imported, and the AOS didn’t crash anymore.
So, when the AOS crashed when you are trying to import an xpo file, stopping the AOS, deleting the ali files from the application directory and restarting the AOS might be the solution.
Now and then, someone comes up to you and says “Could you take a look? There’s an error on my screen”. Mostly, it’s an infolog. And most of the time, you can double click on the message, AX will open the code editor and place the cursor on the line where the message originated. Then, it is either very clear why the message is shown, or you can place a breakpoint to debug the problem.
But sometimes, when you double click on the message, a help window will pop up in stead of the code editor. For example when an error is thrown by the kernel. This can make it difficult to find out where exactly the problem occurs.
Luckily, for every messages that is added to the infolog, the code in the class Info, method Add() is executed. When you put a breakpoint in Info.Add(), the debugger will pop up when a message is added to the infolog, even if they originate in the kernel.
In my opinion, this is the most handy “debugging trick” in AX.
A very common scenario when doing interfaces with other applications, is to have a directory where one application places files, and the other one picks those up and processes them.
Let’s say some application want to interface with Dynamics AX, one way, from that application to AX. That application will drop files of a specific format, say *.txt, in a directory. You’ll want to have a batch job in AX that checks that directory every 5 minutes for those files. When your batch job finds those files, it will open them and do something with that data, then move them to an other directory, so you don’t process them twice.
Now the first thing you’ll probably think of (well, I did…), is to use the class WinAPI. This class has some useful static methods for checking if folders or files exist, finding files with a filename of a certain format. Just the kind of thing we’re looking for. Your code might look like this:
That’s perfect. It checks a directory, in this cas C:\temp, for files with the extension txt… until you try to run this in batch. Your batch will have the status error, and there will be an entry in the event log saying:
RPC error: RPC exception 1702 occurred in session xxx
That error message is very misleading, but Florian Dittgen has a nice blog entry about this, that explains why this goes wrong: WinAPI methods a static and run on client. In batch, you can not use these client methods.
But hey! There is a class called WinAPIServer, surely this runs on server, right? Correct, but a lot of the methods available in WinAPI are missing in WinAPIServer. You can however extend the WinAPI server class by copying methods from the WinAPI class and modifying them a bit. Let’s try that.
This is what the WinAPI::FindFirstFile() method looks like:
As you can see, this method uses the function FindFirstFileW from the Kernel32 dll located in the folder C:\WINDOWS\system32. Let’s copy this method to WinAPIServer and modify it to look like this:
Three things have changed here:
When you test this in batch (running on server), this will work, and you can do this for all WinAPI methods in the examples above… until you try this on a x64 architecture. You’ll receive a message saying that an error occurred when calling the FindFirstFileW function in the Kernel32 DLL (the exact message slipped my mind).
The problem is described on the Axapta Programming Newsgroup. You can code your way around this problem, but I think the message is clear: don’t use WinAPI.
Instead, use the .NET Framework System.IO namespace (watch out for lowercase/uppercase here), in our case in specific, System.IO.File and System.IO.Directory.
I get this nice code example from Greg Pierce’s blog (modified it a bit):
This will run on client and on server without any problems. To have clean code, you could create your own class, just like WinAPI, but using the System.IO namespace. That way, you can reuse this code and save time.
Conclusion: abandon WinAPI, and use System.IO instead.
In the article Wrong argument types in variable assignment, I wrote about how you can solve this error by using compile forward, but doing that won’t always fix the problem, e.g. when using AnyType.
Anytype is great. It’s a primitive data type can use as a placeholder for any other data type, and comes in handy on many occasions. But don’t use it as a silver bullet, it might backfire.
Consider the next example.
We are assigning the current date and time to the AnyType variable, than back to a utcDateTime, and sending it to te screen. This neatly produces following output:
7/04/2009 19:27:15
Now consider the following example.
This produces the following output:
Yes, that’s a blank line. Weird, isn’t it, or is it? MSDN has the answer:
The anytype data types can be automatically converted to dates, enums, integers, reals, strings, guids, int64s, extended data types (records), classes, and containers by assigning a value to the type. […] However, after you have converted the anytype data type, you cannot then change it to another data type.
In the second example it failed to convert the utcDateTime because we assigned a string to the AnyType variable. This is fault very subtle, because no error or warning is shown when compiling such code, and can easily be overlooked.
Not only can (incorrect) use of AnyType cause faulty output, it can also trigger stack traces.
The following example is inspired by Greg.
This will show the following error message and stack trace:
Error executing code: Wrong argument types in variable assignment.
It gets even nastier in the next example:
This will show you a message box saying:
Internal error number 25 in script.
Note: if you are looking to solve the error above (you can encounter it when trying to send an email from code), you can find the links to the hotfixes for ax 2009 here.
And also the error and stack trace we saw before:
Error executing code: Wrong argument types in variable assignment.
Conclusion: Use AnyType with caution, preferably as argument or return type, and remember that the type can not be change once it has been assigned a value.
While doing some modifications to the class SalesFormLetter, I ran into something very strange. I did two simple things:
Adding an object member variable to the class declaration.
Creating a parameter method for this variable.
On compilation, this didn’t show any errors, but when the code was executed, the debugger popped up, and the following error was thrown upon assignment:
Wrong argument types in variable assignment
I recompiled it, ran it again, same error. A colleague took a look at my code and couldn’t find anything wrong with it either, and suggested to stop the AOS and rebuild the .aoi file, but that didn’t do it either.
When I debugged I noticed the the object member journalId didn’t sow up in the list of members in the debugger. A moment after that my colleague asked if I had tried compile forward yet, and I immediately knew that would solve the problem. It did.
MSDN states on several occasions:
It is important to compile forward from the parent class when adding a variable to a classDeclaration of a class that is inherited by other classes.
This was the case with the SalesFormLetter modifications I did.
So always remember to use compile forward when modifying super classes, and it will save you a lot of trouble.
While reading through Wikipedia, I came across something called a quine, and here is its definition:
In computing, a quine is a computer program which produces a copy of its own source code as its only output.
I was inspired by this and decided to make a quine in X++, the programing language of Microsoft Dynamics AX.
It’s a job that finds it’s own tree node in the AOT, gets the source of that node and prints it. I originally wrote it all on one line, because I like the look of that better, but I didn’t do that here for readability.
Now I’m not entirely sure if this qualifies as a quine, because a quine can have no input, and using the method AOTgetSource could be seen as cheating. But anyway, it reproduces itself, it’s short, and it made me happy.