web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

No record found.

News and Announcements icon
Community site session details

Community site session details

Session Id :
Dynamics 365 Community / Forums / Finance forum / Finding layer object i...
Finance forum

Finding layer object is located

(0) ShareShare
ReportReport
Posted on by 670

In AX 2012, we had the ability to do something like this:

TreeNode _treeNode = TreeNode::findNode(@"\path\to\some\object");
var layerMask = _treeNode.applObjectLayerMask();


And it would get the layer(s) that the object existed and customized in, you could then use this to determine if the object was overlayered/customized.

Running this in D365FO though gives a different result, all objects now show as if they are coming from the sys layer regardless of the model they actually come from. I know the idea of 'layers' no longer exist in D365FO but is there a way to see what design time layer an objects exists?

My end goal in all of this would be a way to determine which objects are custom in the environment.

  • Suggested answer
    Joris dG Profile Picture
    17,782 on at

    You need to review your scenario. For development tooling, you should write those in C# using the metadata APIs and create an add-in for Visual Studio. Writing it in X++ would be counter-productive because it implies your code is already written, which is not useful for a development tool.

    If you need this at runtime, then I question what you're trying to accomplish. This no longer makes any sense in AX7+. It has nothing to do with locking overlayering or application sealing, it's just the way it works. When you compile X++ code, it obviously creates 1 binary representation of the code, with all the layers flattened. So as you found out, at runtime layers are meaningless since, well, there are no layers in binaries.

    Layers are a design-time concept, not runtime. Technically that was always the case, but since designtime and runtime where both inside the AOS that line was a bit blurry. Although if you look at the CLR compiled binaries in AX2012, you'll see the exact same thing.

  • alexmeyer.itguy Profile Picture
    670 on at

    Joris, thanks for the response.

    I am looking for a way to determine what objects (menu items, tables, data entities, service operations, etc) are custom/3rd party within a client's environment. If this was to be used internally, the option to add this as an add-in for Visual Studio makes absolute sense. But because this will be deployed to clients I'm not sure I can go that route.

    Unless I'm missing something, I don't think the metadata calls to these objects include whether or not these objects are custom or have any indication whether they are or not.

  • Verified answer
    Mea_ Profile Picture
    60,286 on at

    Customized objects belong to custom models, so you need to list all objects from custom models. Here is a code example https://stackoverflow.com/questions/45598166/how-to-get-aot-objects-tables-for-example-belongs-to-a-model-in-ax7

  • Verified answer
    Joris dG Profile Picture
    17,782 on at

    With over-layering going away, it may be easier if you don't worry about models and can just look at packages (aka modules). You'll want to try something like what Martin blogged about with the Metadata API: dev.goshoom.net/.../new-metadata-api

    Keep in mind the difference between models and packages. Object-to-package info should certainly be in the API - it will also have info about models but i'm not sure if it knows details of each object in what model within the package it came from (and which parts of the object were in what layers/models).

  • Suggested answer
    alexmeyer.itguy Profile Picture
    670 on at

    I used a combination of both Joris and Ievgen's answers and a combination of X++ and C# but was able to come up with the solution below.

    GetModules() - gets all modules with additional info

    You can then filter by the custom modules, and then call GetCustomObjects.

    //X++ class

       public ArrayList GetCustomObjects(ArrayList customModules)
    
       {
    
           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();
    
           Microsoft.Dynamics.AX.Metadata.Providers.IMetadataProvider provider = metadataProviderFactory.CreateRuntimeProvider(runtimeProviderConfiguration);
    
           //IModelManifestProvider modelManifest = provider.ModelManifest;
    
           //var moduleInfoList = provider.ModelManifest.ListModules();
    
           return CustomMetadata::GetModuleCustomObjects(provider, customModules);
    
       }


    // C# class

    public class CustomMetadata
    
    {
    
           public static ArrayList GetModules()
    
           {
    
               ArrayList moduleList = new ArrayList();
    
               var moduleInfoList = Microsoft.Dynamics.Ax.Xpp.MetadataSupport.GetInstalledModuleInfo();
    
               foreach (var moduleInfoKeyPair in moduleInfoList)
    
               {
    
                   foreach(var moduleInfo in moduleInfoKeyPair.Value)
    
                   {
    
                       Module mod = new Module()
    
                       {
    
                           Name = moduleInfo.Name,
    
                           Label = moduleInfo.DisplayName,
    
                           Description = moduleInfo.Description,
    
                           Layer = moduleInfo.Layer,
    
                           Publisher = moduleInfo.Publisher,
    
                           CustomizationLevel = (int)moduleInfo.Customization
    
                       };
    
                       moduleList.Add(mod);
    
                   }
    
               }
    
               return moduleList;
    
           }
    
           public static ArrayList GetModuleCustomObjects(Microsoft.Dynamics.AX.Metadata.Providers.IMetadataProvider provider, ArrayList moduleNames)
    
           {
    
               ArrayList customObjects = new ArrayList();
    
               foreach(var modName in moduleNames)
    
               {
    
                   string moduleName = modName.ToString();
    
                   var customTables = provider.Tables.ListObjectsForModel(moduleName);
    
                   //Other custom objects in model
    
               }
    
           }
    
    }

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

November Spotlight Star - Khushbu Rajvi

Congratulations to a top community star!

Forum Structure Changes Coming on 11/8!

In our never-ending quest to help the Dynamics 365 Community members get answers faster …

Dynamics 365 Community Platform update – Oct 28

Welcome to the next edition of the Community Platform Update. This is a status …

Leaderboard > Finance

Last 30 days Overall leaderboard

Featured topics

Product updates

Dynamics 365 release plans