Saturday, May 30, 2020

Using the product configurator in integration scenarios

Product configuration in D365FO must happen through the user interface, as the product configuration form is the only piece of code that communicates with the solver, wrapped in a dll outside D365FO's X++ codebase. The communication happens through the JavaScript of a designated form control. This is not great if you want to create a configuration in integration scenarios.

In AX 2012 R3 CU8 a class was introduced to allow you to pass a set of attributes and values for these, without using UI parts, and then get the solver to return the XML needed for processing in the backend engine. The class is named PCRuntimeSynchronousConfigurator and you can read a bit about it here.
Even though the solver dll basically is the same between AX 2012 and D365FO, this class didn't make it to D365FO. Well until now, where the class is included in 10.0.12.

So here is an example of how to generate configuration XML for the backend engine:
public static void main(Args _args)
    PCProductConfigurationModel productConfigurationModel = 
        PCProductConfigurationModel::findByName('High End Speaker (D0004)');

    str modelXML = productConfigurationModel.getXML();

    System.String values;
    values = '<Assignments>' +  
             '<Assignment xPath="CabinetFinish" value="Black"' +
             '<Assignment xPath="SpeakerHeight" value="12"' +
             '<Assignment xPath="FrontGrill" value="Metal"' +
             '<Assignment xPath="CornerProtection" value="true"' +

    PCRuntimeSynchronousConfigurator configurator = PCRuntimeSynchronousConfigurator::construct();
    Microsoft.Dynamics.Ax.Frameworks.Controls.ProductConfiguration.IsConfigurationComplete isConfigurationComplete;
    isConfigurationComplete = configurator.configure(modelXML, values);

    if (isConfigurationComplete == 
        str configuredProductXML = configurator.getAllAssignedValues();

Inside the class, the attributes are loaded this way:

Of course you could also previously do what the "new" class does, but it would have been an unsupported and undocumented call to the solver dll and Microsoft could change the dll without any prior notice.

There are a couple of other ways to pass the attributes and values to the solver dll, but they are not supported as no standard X++ code uses these:
    configuratordll.AssignAttributeValueByXPath('CabinetFinish', 'Black'); 
    configuratordll.AssignAttributeValueByXPath('SpeakerHeight', '12');
    configuratordll.AssignAttributeValueByXPath('FrontGrill', 'Metal'); 
    configuratordll.AssignAttributeValueByXPath('CornerProtection', 'true');
    configuratordll.AssignAttributeValueById(2, 'Black');  // Cabinet finish
    configuratordll.AssignAttributeValueById(5, '14');     // Speaker height
    configuratordll.AssignAttributeValueById(3, 'Metal');  // Front grill
    configuratordll.AssignAttributeValueById(4, 'true');   // Corner protection

If you need to implement something like this, I encourage you to check out this flow diagram on docs:
It would be nice if more things were documented with flow diagrams like this.

Wednesday, March 11, 2020

Store your Remote Desktop connection files locally

Today we could experience yet an outtage on LCS, where LCS loses contact to the deployed environments. It took something like a days and a half before things were restored to normal operations.

This means that you can't see any environment details, download RDP files or perform any other environment actions from LCS.

The environments could be running, or you can start them from the Azure portal. But if you haven't stored correct credentials that doesn't get you very far with RDP.

To ensure I can continue development work during another outage likes this, I'll from now on be using a Remote Desktop manager for each of the environments I'm using. That allows me to have the RDP files locally incl. necessary credentials. I'm using the plain one from Microsoft:

The 2LCS tool allows you to easily export the RDP settings for an entire LCS project and add that to the manager.
2LCS is an open source, unsupported, tool maintained by Microsoft. You can get it from GitHub here:
The tool has several other nice features and is much faster to navigate in, compared to the sluggish LCS UI.

For the next outage, I'm prepared.

And for the record, a workaround to this type of issue could also be to add an additional administrator account to the machine from the Azure portal.

Wednesday, January 8, 2020

Label translations not showing in the label search dialog?

Microsoft is now adding translated label files to the deployed developer boxes, which is supposed to make is possible to search for labels in other languages than en-us. I'm not sure if this is done for all models though.

If the search doesn't work, the likely cause is that Microsoft didn't add the related XML file for the language under \AOSService\PackagesLocalDirectory\Package\Model\AxLabelFile.

You can add these manually Here is an example for the Danish SYS label file:

Now search is able to find the Danish labels:

Tuesday, May 21, 2019

"An error occured during report data sets execution" error during printout of production job card

If you get this error during printout of a job card, it could be because the barcode validation didn't pass. Length and content of the barcode is validated during the report generation.

Because of how the failed validation is handled you only see this:

Even though there was actually recorded more information for the infolog:

I have opened a support case for this, and hope it will get fixed.

Monday, April 8, 2019

Workaround to new error during import of security setup

As a new feature to the security setup export and import, Microsoft has added information about objects being disabled/deleted, so the receiving system is able to pick that up too.

But if you both update an object and then disable it, you have created a combination of actions that cannot be imported. This is the error you'll get during import:

The technical reason reason is that the import deals with deleting/disabling objects before it deals with the updates. So when it gets to the update part, it cannot find the object.

The workaround is to pull out your best scissor software and cut out the update part of the XML. Here is an example where I have tried this with the TestEssentialsRole role:

Surprisingly to me is that this, according to MS support, works exactly as designed.

Thursday, April 4, 2019

Missing articles from

Microsoft is apparently doing some spring cleaning and streamlining of their different blogs, so you'll probably notice articles being removed from

Some articles are moved to another blog platform over the spring, and some are just gone.

Well, not totally gone. The Wayback Machine project has been able to help me out with a couple of articles I was missing.

For example this one:

Wednesday, April 3, 2019

Debug external assemblies

Recently I have had the need to understand what was going on inside one of the exchange rate import providers and also the security settings import. Both are only delivered as dll's, which you can find in the bin folder.

To see a decompilation of the code in the assembly, there are several different tools you can use to load it. These are the ones I have some experience with:

They all have that in common that you open the tool, select the dll of the assembly and let the tool decompile it. Here is an example of how that could look for the exchange rate provider I was looking into:

You can also use these tools to look into compiled label files. I sometimes use that when I need to find a particular translation. That could look like this (the language is danish if you wonder):

For the security settings import issue I had a need to debug it to figure what was going on, and in the following I'll try to explain how to do that in the most simple terms as possible.

To be able to debug you need to a have some symbol files. The .NET Reflector Visual Studio integration has a tool for generating these from the compiled dll:

In the following dialog you choose the assembly:

When the PDB's are generated, you can see that a new symbol location has been added to the debugger options:

A few other properties in the debugger options needs to set in a particular way:

Now just add a breakpoint to wherever X++ calls out to the assembly, and you are all set.

Here is a screen clip from a session:

The experience it not totally perfect. The watch windows has problems with some variables and objects because of some "optimization" going on. Check the last link in this article, for a suggestion on how to deal with that.

You must be an administrator to install these tools on the developer box. That means the box must be cloud hosted and not Microsoft hosted.

As an MVP I have been offered a free license of .NET Reflector from Redgate. That is why I'm able to use this particular product for the example.

And I got great value from reading these blog posts, to figure how to setup .NET Reflector debugging:
Disabling Optimizations when Debugging .NET Framework Source Code