Beta exam MB-500

Today I took the beta exam MB-500: Microsoft Dynamics 365: Finance and Operations Apps Developer; I think it’s going to be made generally available on January. I was already planning to take it when I received an email with a significant discount, therefore I had no reason to hesitate.

They didn’t show me my score – they’ll do it „within two weeks after the exam’s live publication date“. But I don’t think I have to worry…

I usually dislike many exam questions – they’re often vaguely formulated, outdated, off the exam topic, testing things that are easy to test but irrelevant and so on.

Questions of this exam are firmly on topic – I don’t remember any where I would question whether the topic itself is relevant. But there are surely things to improve.

Here a few examples:

All answers of one question mention an action in GUI which simply doesn’t make sense, so technically neither answer is correct. It’s clear that the actual question was about something else, but it may be confusing and it doesn’t look very professional.

In one lab, the ALM process described there doesn’t make a good sense to me and it goes directly against Microsoft best practices, therefore I don’t think it’s a good idea to put it there. Then you must answer questions not based on how things should be done in practice, but what fulfills the artificial restrictions – and hope that authors of the exams didn’t forget about them when defining “correct” answers.

In one question, I was asked to implement a very common piece of code, but the options didn’t include any of the ways how it’s normally done. What I assume is the right answer is technically correct, but nobody would ever do it and I don’t believe that many people remember the method – I didn’t it. I’m convinced that this isn’t what exams should test.

I also found some basics mistakes in code, such as incompatible types that would cause failure already on compilation, or answers that can be correct or not depending on context (which wasn’t provided).

After taking an exam, there is time for evaluation and I was keen to cover all these points in detail there. But the time allocated was completely insufficient; then it simply kicks you off. And when I got a warning popup that I had only one minute left, the UI became unresponsive and I was unable to complete at least the thing I writing at the moment. Effectively, I got even one less minute that intended.

It sounds pretty strange to me – you invite somebody to take a beta exam and give you feedback, but they you make providing detailed feedback impossible. The time slot for evaluation should be longer – even for regular exams, but especially for beta exams that should be all about collecting feedback. And a bit more review of technical correctness wouldn’t harm either.

Calling async method from X++

There is a trend in the .NET world to make time-consuming calls asynchronous, to prevent applications from getting blocked when waiting for a response from a web service and things like that. Many existing APIs were enhanced with asynchronous variants of previously synchronous actions and some newer APIs offer only asynchronous methods. So… how can we call such asynchronous methods from X++?

For a demo, imagine that I want to read the content of a file. I can use StreamReader.ReadToEnd() or the asynchronous alternative, ReadToEndAsync().

ReadToEnd() returns a string, therefore I can simply assign the result to a string variable.

str file = "devenv.exe.config";
 
using (var reader = new System.IO.StreamReader(file))
{
    str s = reader.ReadToEnd();
}

By the way, the code is written for F&O, where we can simplify our code with using and var keywords, but the core logic can be used in older versions of AX as well. .NET Interop as such was introduced in AX 4.0.

ReadToEndAsync() doesn’t return a string, it returns a task returning a string (Task<string>). A task represent a piece of work to be done, in this case reading the file. In normal .NET development, you could use threads for parallel processing for a long time before tasks (Task Parallel Library) were introduced, but tasks make it all much easier. It’s been further enhanced by adding async and await keyworks to languages such as C#, which allows writing code for dealing with asynchronous methods in a very succinct way.

We don’t have async/await in X++, but we surely can work with tasks directly. When I call an async method, I get a task object and the easiest thing I can do with it it is waiting for completion and then accessing the result:

str file = "devenv.exe.config";
 
using (var reader = new System.IO.StreamReader(file))
{
    var task = reader.ReadToEndAsync();
    task.Wait();
    str s = task.Result;
}

I’ll get exactly the same result as in the synchronous variant mentioned above.

This is actually a synchronous execution of an asynchronous API, therefore it doesn’t bring many advantages for parallelism, but it’s often what you want anyway. For instance, you call your logic from a batch job (you don’t mind blocking), you can’t continue without the result and the API doesn’t support synchronous operations.

You can build something more interesting on top of this simple example. For instance, you can create several tasks (without calling Wait()), put them into an array and then use Task.WaitAll() to execute all of them at once (in parallel if possible) and wait for completion.

To make things truly asynchronous, you would need callback methods instead of waiting for completion.

String format options for utcDateTime

I’ve run into a problem that reminded me that while X++ types and corresponding CLR types (such as str and System.String) can often be user interchangeably, they aren’t the same.

I was trying to convert a utcdatetime value to the standard “sortable” format in D365FO, for which I wrote the following code:

utcdatetime currentDateTime = DateTimeUtil::utcNow();
str s = System.String::Format('{0:s}', currentDateTime);

What I expected was something like 2019-02-03T17:29:00, but I got a very different format – 02/03/2019 17:29:00. What was wrong with my code?

The format definition is all right… but I don’t have the right type! I can easily fix the problem by declaring currentDateTime as System.DateTime instead of utcdatetime.

System.DateTime currentDateTime = DateTimeUtil::utcNow();
str s = System.String::Format('{0:s}', currentDateTime);

When Format() method is called, it’s able to utilize special formatting options (such as the “s” format), if the type of the value has methods that knows what do to it with it. System.DateTime knows what to do, but utcdatetime is actually Microsoft.Dynamics.Ax.Xpp.AxShared.utcdatetime structure which isn’t able to handle these options. It has a single hard-coded format for converting the datetime value to a string.

While I’m still working with the same value in both utcdatetime and System.DateTime, they’re two different types with different behavior and a conversion may be needed if I need behavior specific to only one of them.

I tested this behavior on Platform Update 22 and 24.

Splitting .xpo files

I got an .xpo file from an older version of AX with some code of interest and because it had a few thousand lines, it wasn’t exactly easy to navigate. At least splitting it by object would make my life much easier.

Fortunately I looked at the internet and found exactly the right tool for this task: xpoTools.

It’s not well-documented, but what I needed didn’t require much anyway. After installation, I simply ran the following (Powershell) code:

cd c:\Temp\XPO\
ls *.xpo | Import-Xpo | Split-Xpo -Xpp

Import-Xpo parses xpo files to objects expected by Split-Xpo, which creates a file for every object. The -Xpp flag means that the result are not .xpo files, but rather more readable files with pure source code (without all those # characters and things like that).

This might be the last time I used this tool, but it did help me today. As often, a single search on internet saved me a lot of time.

Thank you, mazzy.