Data import random error – Method not found

Moving data between different instances of Dynamics 365 should be relatively easy with the Data Management framework. Microsoft offers a long list of entities and default templates nicely grouped into relevant packages.

In 7.2 we did experience some issues with loading the default templates, but that seemed fixed in 7.3.2. The real problems showed up when trying to import the packages in projects created based on the export file.

It seemed like after importing file number one or two the Data Management forms got corrupted with an error stating: “Method not found: ‘Dynamics.AX.Application.FormBuildControl Dynamics.AX.Application.FormBuildControl.parentControl()’.”

Method not found

All other forms checked worked. After a full compile we were back on track, but that really wasn’t a working solution with multiple packages to import.

Debugging the forms didn’t add anything valuable to the troubleshooting. Going back to start and breaking it up into smaller chunks it appeared too random to be data driven as first suspected.

The solution – don’t ask how I ended there – is like this:

After each package I cleared the browser cache and refreshed the tab running my Dynamics 365….

Clear browsing data

And here a little pitch of Google Chrome that allows you to only clear the most recent part of the data:

Clear browsing data - last hour

It adds a bit of overhead to the data import having to do this step between each package; but nothing compared to the alternatives.

 

Advertisements

Roaming AUC files – new feature in R3

The quest for increasing performance in AX appears never-ending. With AX 2012 R3 Microsoft has added a new tool allowing us to make the AUC files global/shared.

Basic AUC file info:

AUC files are cache files made by the AX client to improve load time. Forms we have already loaded once could be loaded again from the cache without having to make a trip to the AOS for the bits and bytes. All stored in c:\users\<username>\AppData\local and then by nature user specific.

So the main challenge so far has been that user A opens the sales order form the first time, waits, caches the element and can open the form faster the second time and the same story for user B, C and all the others.

In AX 2012 R3 a new feature have been added to the client configuration with the title “Use roaming user profile to store client-side cache”. That basically says it all. We can now specify a global directory for the cache files allowing users to share the cache so when user A has opened the form user B can utilise the cache.

Still no fun for user A, but user B is in luck …

Caching display methods in forms

This post is probably not the most earth shaking news but still a relevant issue to visit once in a while.

When developing or customising forms we often have to put in display methods to show the user data not available directly from the datasource. That can be either data from related tables or the result of calculations. For each refresh of data the display fields will be updated and the content recalculated. This can result in a significant performance plunge which easily can be fixed.

I did a quick test and in the Customer group form with 7 records a display method is called 27(!) times just opening the form. If your display method is the first column in the grid you can actually add a couple of clicks to that number.

So there definitely motivation enough here to spent a few moments on this. So let us start by separating the display method into two categories: Form methods and table methods.

Caching table methods

This is the easy one. Go to the init method on the datasource and add the following piece of code after the super() call:

CustGroup_ds.cacheAddMethod(tableMethodStr(CustGroup, cacheTestTableCached));

That is it. Your table display method is now cached and in the above example goes from 27 to 7 clicks.

Caching form methods

In this example we have a display method on the CustGroup datasource looking like this:

display Description paymTermDescription(CustGroup _custGroup)
{
    return PaymTerm::find(_custGroup.PaymTermId).Description;
}

With the earlier mentioned example this data lookup will be performed 27 times for 7 records. Here we need to do a couple of lines of coding to do make this work. First of all we need a Map object in the form declaration method:

public class FormRun extends ObjectRun
{
    Map cacheDemo;
}

Then we change our display method to look like this:

display Description paymTermDescriptionCached(CustGroup _custGroup)
{
    if (! cacheDemo)
    {
        cacheDemo = new Map(Types::String, Types::String);
    }
    if (! cacheDemo.exists(_custGroup.PaymTermId))
    {
        cacheDemo.insert(_custGroup.PaymTermId, PaymTerm::find(_custGroup.PaymTermId).Description);
    }
    return cacheDemo.lookup(_custGroup.PaymTermId);
}

Let us break down what the method does now.

  1. First we make sure that the Map object cacheDemo is instantiated. This could be done in the forms init method instead.
  2. Then we check if we already have the value we need in the cache. This is done based on the PaymTermId field on the CustGroup record. If it is not found we add it to the cache.
  3. Finally, we lookup the value from the cache and returns it. We know that the value always is in the cache so no need to do an exists check again.

This means that we still hit the display method as many times as before; but the calculation/data search part is only executed once per Payment term id. In this case that makes it 6 clicks since to customer groups had the same Payment term id.