Dynamics 365 Saturday South Africa

I’m safely back in Prague and I would like to thank everybody who attended Dynamics 365 Saturday in Johannesburg. There were so many of you!

And I want to give special thanks to people who did all the work to make the event happen and those who cared of me there. This was my first visit to South Africa and it was great you showed my lions, local food and everything.

I hope that my talks (about .NET in D365FO and about design for extensibility) gave people some useful information.

Dynamics 365 Saturday isn’t limited to South Africa, of course. There are quite a few already scheduled, therefore check what’s going in your area. It’s all free!

Weird behaviour after moving a form to another package

I recently had to move a form to another package, because we decided to extract some functionality to its own independent package. I moved files, built both packages and everything looked fine, so I started making changes for a new requirement.

But later I noticed something strange in the form. When I opened the form, it didn’t look right. Some new controls (added after the move) were missing and other parts behaved incorrectly (I won’t go into details here). Everything went back to normal when I refreshed the page, but the problem appeared again when I opened the form from menu. Using the refresh button inside the form (beside buttons Open in Microsoft Office and attachments) end up with an error and the application froze.

After making sure that everything is built correctly and restarting everything, I duplicated the form and tried the copy. It worked flawlessly, proving that the form itself was implemented correctly. Therefore, I suspected that the environment somehow used a cached design of the form as it was defined in the old package. Building the packages with and without Build Pre-Compiled Form didn’t make any difference, so I tried one more thing.

I searched the packages directory for the name of my form and I did find something suspicious. There was a file in WebContent subfolder of the original package:

[…]\PackagesLocalDirectory\MyOriginalPackage\WebContent\Forms\myform.json

Just deleting the file didn’t fix the problem, but restarting the server after that did. It would be likely sufficient to restart IIS; I turned the whole machine off because I went home and tried the result the next day.

I wanted to write this down because others might run into the same problem. And it looks like a bug in Microsoft tools, therefore they should look at it and fix it.

XML response from OData services

If you call OData services in AX 7 (Dynamics 365 for Finance and Operations), you typically get data in JSON format, like this:

{
  "@odata.context":"https://myaxinstance.cloudax.dynamics.com/data/$metadata","value":[
    {
      "name":"ElectronicPaymentTypes","kind":"EntitySet","url":"ElectronicPaymentTypes"
    },{
      "name":"ExpensePaymentDetails","kind":"EntitySet","url":"ExpensePaymentDetails"
    }
    ...
  ]
}

JSON is a simple, lightweight format with good support in many tools, but sometimes you would rather get XML. XML is by no mean deprecated – it’s more than a format; you get a whole platform with capabilities useful for validations (XML schema), querying (XPath, XQuery), transformations (XSLT) and so on. Or you simply have a component that accepts only XML and not JSON.

Fortunately OData services aren’t limited to JSON; they can return XML as well. Simply add HTTP header Accept with value application/atom+xml,application/atomsvc+xml,application/xml and you’ll start getting the same data in XML format:

<ODataServiceDocument xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/Microsoft.OData.Core">
  <EntitySets>
    <ODataEntitySetInfo>
      <Name>ElectronicPaymentTypes</Name>
      <Title i:nil="true" />
      <Url>ElectronicPaymentTypes</Url>
    </ODataEntitySetInfo>
    <ODataEntitySetInfo>
      <Name>ExpensePaymentDetails</Name>
      <Title i:nil="true" />
      <Url>ExpensePaymentDetails</Url>
    </ODataEntitySetInfo><ODataEntitySetInfo>
  ...
  </EntitySets>
</ODataServiceDocument>

If you use Postman, for example, this is where you can put the header:

Of course, that you get XML format doesn’t mean that you get the structure you want. You still may need to transform it to something more suitable for your purposes.

The problem is that seems to be respected only at the highest level, i.e. the list of available services. The individual services return JSON regardless of the header.

‘Get latest’ failed on a file without permissions

A few days ago I was getting latest changes from VSTS to an AX 7 development box when it failed on a certain (custom) .dll file, because Visual Studio wasn’t able to overwrite the file.

I made sure that all AX services are down, but it made no difference. Then I looked at file permissions and found that I didn’t have any permissions at all, which was really weird. I did use the environment a few weeks ago without problems.

Ultimately I restarted the server and the file disappeared, therefore I was able to get the new version from VSTS without issues. It seems that the file was technically already deleted and I just saw some strange state of the system.

If I see something similar next time, restarting the machine will be one of my first steps.

Recurring Integrations Scheduler: File already exists

I’ve recently run into a problem with Recurring Integrations Scheduler and I think I won’t be the only one, therefore I’m going to explain it here.

The Recurring Integrations Scheduler (RIS) supports both the old recurring integrations API (enqueue/dequeue) and the new package API, which is the recommended approach. With the package API, you can either import whole packages (which you must prepare by yourself in some way) or you can give RIS actual data files (XML, CSV…) and let it build packages for you. That’s the scenario I’m talking about below.

If you want RIS to create packages, you must give it a package template. Go to the Data Management workspace in AX 7, create an import job, configure it as you like and then download the package. I’m using the Customer groups entity as an example.

You’ll get a file with a GUID as the name, such as {99DD43E4-936E-4402-80E6-1477013A5275}.zip. Feel free to rename it; I’ll call it CustGroupImportTemplate.zip.

This is its content:

You can see one data file for the entity (Customer groups.xml in my case) plus some metadata defining the import project.

It’s not exactly what’s needed, as we’ll see later, but let’s continue for now with this package.

Go to RIS and configure an import job. Don’t forget to set Package template to the package file.

Make sure the job is running, create an input file in the right format and put it into the input folder.

Unfortunately the import fails and you’ll find these files in the Processing errors folder:

The status file merely says that StatusCode = BadRequest and events logs for RIS (Applications and Services Logs > Recurring Integrations Scheduler) don’t reveal anything else either. More useful event logs are under Applications and Services Logs > Microsoft > Dynamics > AX-OData Service, where you can find something like this:

System.InvalidOperationException: Exception occurred while executing action ImportFromPackage on Entity DataManagementDefinitionGroup: The file ‘C:\windows\TEMP\005DE7CC-C7E8-410D-8690-7A63C30224BF_FF5EE0BE-205C-48BC-8987-96C007CE74ED\Customer groups.xml’ already exists.

A unique folder name is generated for each import, therefore the problem isn’t related to existing files in the Temp folder.

To make it short, the problem is in the package file itself, which you unfortunately never see, because it’s automatically deleted on failure. If you captured it and looked inside, you would find this:

There are literally two files with the same name and therefore the attempt to unpack the archive fails on the second instance.

How does this happen?

One file is coming from the package template. The other is the input file, which RIS renamed to match the entity name and added to the archive. Having files with same names is supported by ZIP, but the library used by RIS for unpacking isn’t able to handle it.

To get it working correctly, you must remove the data file (Customer groups.xml) from the package used as a template. A better solution, though, would be modifying RIS to replace the file instead of attaching another file with the same name.