AX 7 (“Microsoft Dynamics 365 for Operations”) offers a new API for getting metadata of AX elements such as tables, form extensions, models and so on. It’s very easy to use, therefore even if you’re very familiar with the old TreeNode API, you should definitely pay attention to this new one.
The best place to start is in the MetadataSupport class in Microsoft.Dynamics.Ax.Xpp namespace (yes, the whole API is in an external library; it’s not written in X++).
The class offers many static methods providing information about elements. Taking tables as an example, you can use:
- TableNames() to get a list of names of all tables in Dynamics AX.
- GetAllTables() to get details of all tables as objects.
- GetTable() to get details of an individual table (based on its name or ID).
The MetadataSupport class also offers a few helper methods such as IsTableMapped() and ConvertAxUserTypeToBaseType().
Element details are represented by classes with names prefixed with Ax. For example, GetTable() returns an instance of AxTable class. (All these classes are defined in another assembly; the namespace is Microsoft.Dynamics.AX.Metadata.MetaModel).
These classes provide all details you may need. For tables, you can see properties, fields, indexes, methods and everything else.
Let me give you a full example that you can take and run in your environment. It iterates all controls in a given form and put their names to infolog.
using Microsoft.Dynamics.AX.Metadata.MetaModel; class MetadataDemo { public static void main(Args _args) { AxForm form = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetForm(formStr(SysUserSetup)); new MetadataDemo().showControlNames(form.Design); } private void showControlNames(IFormControlCollection _control) { var controlEnumerator = _control.Controls.GetEnumerator(); while (controlEnumerator.MoveNext()) { AxFormControl control = controlEnumerator.Current; if (control is IFormControlCollection) { this.showControlNames(control as IFormControlCollection); // Recursion } else { info(control.Name); } } } }
There are a few things to notice:
- It starts with using Microsoft.Dynamics.AX.Metadata.MetaModel, so we don’t have to repeat this namespace when referring to classes such as AxFormControl.
I didn’t bother to do the same with Microsoft.Dynamics.Ax.Xpp, because I’m referring to it just once. - I use IFormControlCollection interface instead of concrete classes when I need to work with something containing child controls. This allows me to use the same code for the Design node as well as for container controls such as tab pages, because they all implement this interface. Such interfaces are extremely useful for writing generic code and fortunately they’re used quite a lot in this framework.
- Notice that AX 7 allows us to use property names directly (e.g. form.Design), so we don’t have to resort to the underlying accessor methods (e.g. form.get_Design()) as in previous versions . It makes programming easier and code nicer.
- As a side note, notice the comment pointing out the recursive call. I tend to always do that, to make the use of reflection immediately obvious.
I truly enjoy working with this new metadata API – it’s nicely designed and easy to use. The only problem might be that you need to be a bit familiar with .NET Interop (= accessing .NET objects from X++), but even if you aren’t, you’ll quickly learn those few things you need.
Thanks again for an excellent post! I was still grieving the loss of the old APIs for this, but this looks like just what we need. I see curious methods like AddMethod and such on these APIs in your screenshots. Can you really add metadata such as tables, classes and methods to a running application using these techniques??
I don’t think you can do it at runtime, but you can write Visual Studio add-ons doing such changes (then you need compilation etc.). You can see a crude example here: https://github.com/XppDevs/vs-addin/blob/master/XppDevs-Addins/AddinsDemo/AddinsDemo/AddMethodDesignerAddIn.cs
Thank you! Very useful post!
Martin, could you give me advice about how can I find references to some object? For example, I have a table and I want to find all references to this table (like in Visual Studio menu item “Find references”) using metadata API?
Thanks!
Hi Martin,
Let’s say I’ve used the metadata API to find a specific AxFormControl of interest in the CustTable form. Is there a way to use this AxFromControl to lookup the actual control on a FormRun Instance?
As AxFormControl dosen’t have an id().
eg. formrun.design().control(axformControl.id()).setFocus();
Hi Martin,
I want to get all the display menuItems from menus how can I do this using metadata API ?
You already have a thread in the community forum, therefore let’s keep the discussion there.
Yes, but I don’t get any reply about metadata.
Hi Martin,
Thanks for helfpul post,
please i have quick question i want to iterate the MenuExtensions provider,
Here is my code:
var environment = Microsoft.Dynamics.ApplicationPlatform.Environment.EnvironmentFactory::GetApplicationEnvironment();
str packageDir = environment.get_Aos().get_PackageDirectory();
var runtimeProviderConfiguration = New Microsoft.Dynamics.AX.Metadata.Storage.Runtime.RuntimeProviderConfiguration(packageDir);
var metadataProviderFactory = New Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory();
var provider = metadataProviderFactory.CreateRuntimeProvider(runtimeProviderConfiguration);
CLRObject extendedMenus = provider.MenuExtensions;
var listEnumerator = extendedMenus.getEnumerator();
While (listEnumerator.moveNext())
{
// Here i want iterate each AxMenuExtension menu in listEnumerator
//AXMenuExtension menuExtension;
}
My code at on : var listEnumerator = extendedMenus.getEnumerator();
Hi Anonymous, Check Dynamics Community forum
Hi Martin,
This is good article which i used in my development.
One quick question is how to get label of the form control. I have AxFormControl object which has no function to get the label. Please help.
Thank you.
Hi,
I extended a form and added a new datasource, but using this API, the new datasource is not listed. Is this API not working with extensions?
The metadata API supports extensions, but you need to choose whether you want to get them or not. Note that MetadataSupport is just a simplified interface and it doesn’t expose all features of the API.
For example, this will create a provide with extensions applied:
using Microsoft.Dynamics.ApplicationPlatform.Environment;
using Microsoft.Dynamics.AX.Metadata.Storage;
using Microsoft.Dynamics.AX.Metadata.Storage.Runtime;
...
str packageDir = EnvironmentFactory::GetApplicationEnvironment().Aos.PackageDirectory;
var runtimeProviderConfiguration = new RuntimeProviderConfiguration(packageDir);
var provider = new MetadataProviderFactory().CreateRuntimeProviderWithExtensions(runtimeProviderConfiguration);