In X++ you can optionally declare a string to have a specified maximum length:
str 5 maxLen5String;
Semantically, if you try to store more than 5 characters to this string, it will be truncated.
In March 2010 we blogged here about the X++ max-length string type, and asked how we should handle it in Microsoft Dynamics AX 2012. This became an issue when we began to compile X++ into .NET Framework CIL (Common Intermediate Language). X++ has the concept of a max-length string, but CIL does not. Thus an inconsistency in behavior was to be introduced. X++ max-length strings are truncated as necessary when the X++ runs in interpreted mode, but they are not truncated when the X++ runs as CIL.
Respondents to our earlier blog were generally indifferent to whether we truncated strings in interpreted X++ or not. But we were also concerned about backward compatibility. After much discussion we decided that interpreted X++ should continue string truncation in AX 2012, just as it has done in earlier versions of AX. In other words, we were willing to live with the inconsistency with CIL.
However, as part of this discussion we wanted to be able to easily analyze this to better understand what this inconsistency would mean in real-world code. To that end, we added an option to log where string truncation was actually happening in the interpreter (and, by extension, where it would not be happening in CIL).
We found this option to be so beneficial that we decided to productize it so that everyone could benefit.
New Option to Log String Truncations
The name of the new switch that activates the logging of string truncations is logstrtrunc. The switch is honored by both the AX client and the AX server. Logstrtrunc is off by default since there is some performance cost associated with it.
As with most AX option switches, logstrtrunc can be specified on either the command line or in the Windows Registry. Whenever the command line and the Registry conflict, the command line value takes precedence.
Command Line Syntax
Note: /logstrtrunc is invalid syntax. The option name must be preceded by a dash (-).
Alternatively, an optional Windows Registry key for the logstrtrunc option can added, either manually using regedit.exe, or by double-clicking on a .REG file containing the following data:
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Dynamics\6.0\Configuration\Original (installed configuration)]
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Dynamics Server\6.0\01\Original (installed configuration)]
The first key contains the path node of \Dynamics\, indicating that it applies to the Ax32.exe client. The second key contains the path node of \Dynamics Server\, indicating that it applies to the Ax32serv.exe server. Either or both may be specified. The registry key option is especially useful for the Server (AOS), which is usually run as a service and not from the command line directly.
After these keys are in the Registry, you can turn this logstrtrunc option off and on by toggling the dword value between 0 and 1 respectively. Remember to disable the key after you are done testing to avoid any performance impact.
The client and server read these Registry keys only when they start running, so you will need to restart the session before your change will take effect.
Effect of logstrtrunc Option
When the logstrtrunc option is on, every time an X++ max-length string gets truncated, the system writes an entry to the Application section of the Windows Event Log. You can view these entries by using the Windows Event Viewer. In each entry the Source and Event ID values are as follows:
o Client: "Microsoft Dynamics AX"
o Server: "Dynamics Server 01"
· Event ID: 191
These values are very useful for filtering and sorting when you want to locate the relevant log entries in the event log. Of course, if your X++ code contains no max-length strings or if none of the assignments to your max-length strings exceed the length boundaries, nothing will be written to the log. We will now focus on what to do if log entries do show up.
Code Example and Sample Log Entries
Here is a simple X++ job which assigns excessively long values to a max-length string. Assume you run this job in interpreted mode with logstrtrunc on:
1 // Compile and run this X++ job to see two different forms of string truncation.
2 static void Job1(Args _args)
4 str 5 maxStringBuffer; // Maximum length is 5.
6 maxStringBuffer = 'Hello world'; // Assignment leaves maxStringBuffer == 'Hello'.
7 maxStringBuffer += ' there world'; // Append attempt leaves maxStringBuffer == 'Hello'.
Code line 6 attempts the assignment of an excessively long string which will be truncated. The body of the event log entry message displays the whole value that the X++ code attempted to assign so that you can see what was truncated:
X++ str 5 buffer truncated during assignment:
(C)\Jobs\Job1 - line 6
Code line 7 attempts to make the concatenation of two strings be the new value of a maxStringBuffer. In this case the message displays both strings that were involved in the concatenation so that you can figure out what got truncated:
X++ str 5 buffer truncated during concatenation:
(C)\Jobs\Job1 - line 7
Notice that a stack trace is included, which is very helpful in more complicated examples.
Assume your system has several log entries from logstrtrunc being on. These entries could result for a number of different reasons.
The following table categorizes some possible causes of those log entries and in each case a possible approach that can eliminate the automatic truncation of strings (and eliminate future log entries). In many cases, this will allow you to fix real “bugs” and also eliminate any discrepancies when run interpreted versus run as CIL:
Reason for using maximum-length string
Testing automatic truncation.
Remove the X++ logic before deploying to production.
No good reason.
Perhaps erase the max-length specifier from the declaration of the X++ string variable.
Purposely relying on automatic (implicit) truncation.
Add logic to your X++ code to explicitly truncate the max-length string as needed.
Then eliminate the max-length specifier from the declaration of the X++ string variable.
Max-length intended to match table or form field length.
Consider whether the table field is actually long enough. You might lengthen the field so that no more truncations are needed. Or, you might have to shorten the length of the content your code assigns to the string or field.
EDTs are a common example of max-length strings of that exhibit this behavior.
String content is longer after translation from into a foreign language (localization or globalization)
A string in your native tongue that easily fits into an 80 character buffer might need a buffer of 100 characters or more in another language.
Truncations in this situation suggest a bug in your X++ code, regardless of CIL. Running scenarios with localized versions of the product is a great way to benefit from the logstrtrunc option.
In a few cases, such as displaying long path names, it can be appropriate to provide a “pretty” truncation. For example, the following shortened representation of a full path conveniently conveys the information that the reader needs most:
In such cases you should substitute your own truncation logic instead of letting the interpreter perform automatic truncation.
Try Various Scenarios
With logstrtrunc on in your test environment, run several different scenarios to give all possible string truncation code the greatest likelihood of truncating and thus being logged. Scenarios that involve localization can be very important to test. The resulting log information should enable you to understand and eliminate any unwanted automatic truncations that can occur when X++ runs in interpreted mode.
In summary, the logstrtrunc option makes it easy for X++ developers to track down any potential string truncation discrepancies associated with compiling X++ to .NET CIL.