Skip to content

XML DocType in X++

Let’s say that we want to use X++ to create an XML file with the following DocType definition:

<!DOCTYPE MyType SYSTEM "http://www.validome.org/check/test.dtd">

AX has Xml* classes (e.g. XmlDocument) for such purpose, but let’s build it with .NET classes first (you’ll see why in a moment). This is X++ code calling .NET classes through .NET Interop:

System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.AppendChild(xmlDoc.CreateDocumentType('MyType', null, 'http://www.validome.org/check/test.dtd', null));
info(xmlDoc.get_OuterXml());

The output is exactly what we want.

Now let’s try to rewrite it with native X++ classes:

XmlDocument xmlDoc = new XMLDocument();
xmlDoc.appendChild(xmlDoc.createDocumentType('MyType', '', 'http://www.validome.org/check/test.dtd', ''));
info(xmlDoc.xml());

Notice that it’s very similar to the previous example, but we had to replace null values with empty strings (”), because X++ doesn’t support null-valued strings.

The output is not correct in this case:

<!DOCTYPE MyType PUBLIC "" "http://www.validome.org/check/test.dtd"[]>

We can easily prove that the empty strings are to blame by rewriting our .NET-based example to use empty strings instead of nulls:

System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.AppendChild(xmlDoc.CreateDocumentType('MyType', '', 'http://www.validome.org/check/test.dtd', ''));
info(xmlDoc.get_OuterXml());

The output is identical to what we get from X++.

Let me explain what’s going on.

If you provide a value for publicId (the second parameter), the PUBLIC keyword is used, followed by the URI provided in publicId. That applies to empty URI as well, so we get:

<!DOCTYPE MyType PUBLIC "" (…)>

If you want to get SYSTEM keyword, publicId must be null, not “”. The fourth parameter, internalSubset, is a similar case.

Even if you aren’t familiar with .NET at all, you likely understand the difference between a null reference (x = null) and an empty object (x = new Object()). Unlike in X++, strings in .NET are objects (instances of System.String class) and therefore they can either refer to a value or be without any value at all (= null).

Now what we can do to set null values to XmlDocument.createDocumentType()? Well… nothing. All parameters are X++ strings and null isn’t a valid value for them. It would have to be designed differently, e.g. using strings wrapped in objects or providing an additional flag to say that the value should be ignored.

The workaround is simple – you can use .NET classes (from System.Xml namespace) as in the first code snippet.

Tested in AX 2012 R3.

Operand types are not compatible

I managed to produce a really confusing error in AX 2012. Look at the following piece of code:

MyExtendedDataType a, b;
a = b;

Pretty boring, isn’t it? There is nothing to fail… except that I got a compilation error: Operand types are not compatible with the operator. What?

Actually it become quite clear as soon as I simplified my code to this trivial example. There is clearly nothing wrong with my code, it must have something to do with the data type.

To make a long story short, I created a new extended data type of type enum and forgot to fill in the EnumType property. Linking the EDT to an enum instantly solved the problem.

But beware – the compiler won’t detect many other uses of this incorrectly-defined type. For example, MyExtendedDataType a = NoYes::Yes; is compilable X++ code even if MyExtendedDataType has empty EnumType.

Compile backwards

Today I noticed that Type hierarchy browser in AX 2012 R3 allows you to compile types backwards:

HierarchyBrowserCompile

Context menu in AOT supports only forward compilation.

It’s possible that the feature is there for some time and it just took me long time to notice it, because I normally don’t compile code from Type hierarchy browser.

Stakeholder license for Visual Studio Online

Brian Harry announced some upcoming changes in licensing of Visual Studio Online (and later for Team Foundation Server too). Everybody should be delighted by the new Stakeholder license, which will be completely free. It will have following permissions:

  • Full read/write/create on all work items
  • Create, run and save (to “My Queries”) work item queries
  • View project and team home pages
  • Access to the backlog, including add and update (but no ability to reprioritize the work)
  • Ability to receive work item alerts

That’s a lot of things that people can do without any cost, isn’t it? Now everybody will be able to participate in a VS Online / TFS project without any special licensing requirements.

Issue Search

Issue Search is obviously not the coolest part of Microsoft Dynamics Lifecycle Services, but it’s very useful and I would like to show you a few tricks.

If you’ve never heard about Issues Search before, it’s a relatively simple web page where you can find hot fixes released for AX 2012 and even issues currently being investigated. This is how the main page looks like:SearchResults

You can see that there is a text box for search input, some filters and results. Notice that you can filter by version of AX (you sometimes need to open Advanced search and adjust this setting to get what you want), that different states of issues have different colors and that you can directly see KB number and the release date (if applicable).

If you click on an issue, you’ll see a bit more details and most importantly you’ll be able to download released hotfixes.

IssueDetails

Often you can even see changes done by Microsoft in X++ code, which allows you to quickly review the solution and impact on your application (by using View changes or clicking on a particular affected object).

CodeChanges

If you’re familiar with Team Foundation Server, you probably know that this web-based code comparison is a standard feature, so it’s not something unique to Dynamics Lifecycle Services. But it’s unusual to see such a level of transparency from software vendors and I must appreciate that Microsoft decided to share all these details with us.

Now if you return to the main page, you can see the following suggestion in the input box: Enter a keyword, KB number or AOT object path ($\ObjectType\Object or $\ObjectType\Object#element, e.g. $\Classes\Tax#post). If you suspect that something is wrong in a specific object or method, you can easily find all related fixes:

preRunModifyContract

I also noticed that in AX 2012 R3 you can open Issue Search for a given object directly from AOT.

AOTContextMenu

Just note that this currently works only for root elements, not for individual methods.

I never enjoyed searching for hotfixes on PartnerSource; Issue Search is so much better. I don’t say it’s perfect, but it’s evolving, together with the rest of Dynamics Lifecycle Services. And you can help it to evolve by sending some feedback to the product team – just use the smiling icon in the top right corner. Smile

I can tell you from my experience that they don’t ignore feedback (which, of course, doesn’t necessarily mean that your favorite feature will get on the top of their backlog).