Modifying D365FO metadata using reflection

As part of our code upgrade to Dynamics 365 Finance and Operations we have removed some processes, for which the security roles had to be refreshed en mass. For this I have decided to go with modifying D365FO metadata using reflection to see how can we do it with the new file-based repository.

modifying D365FO metadata using reflection

First I have created a new C# project and referred the following 3 Dynamic Link Libraries from the AOSService\PAckagesLocal\bin folder:

Microsoft.Dynamics.AX.Metadata
Microsoft.Dynamics.AX.Metadata.Core
Microsoft.Dynamics.AX.Metadata.Storage

Then the following code was developed, which shows how to manipulate the metadata using the new DiskMetadataProvider classes. In the example below we were working against the JADOperation package and AxSecurityRole objects.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Dynamics.AX.Metadata.Storage;
using Microsoft.Dynamics.AX.Metadata.Core.Collections;
using Microsoft.Dynamics.AX.Metadata.Providers;
using Microsoft.Dynamics.AX.Metadata.MetaModel;
 
namespace ModifyAOT
{
    class Program
    {
        static bool removeNode(
            AxSecurityRole _role,
            KeyedObjectCollection<AxSecurityPrivilegeReference> _privs,
            string _node
            )
        {
            bool isModified = false;
 
            if (_privs.Contains(_node))
            {
                Console.WriteLine("Removing " + _role.Name + "." + _node);
                _privs.Remove(_node);
                isModified = true;
            }
 
            return isModified;
        }
 
        static void Main(string[] args)
        {
            string packagesLocalDirectory = @"C:\AosService\PackagesLocalDirectory";
            IMetadataProvider diskMetadataProvider = new MetadataProviderFactory().CreateDiskProvider(packagesLocalDirectory);
 
            var l = diskMetadataProvider.SecurityRoles.ListObjects("JADOperation");
            var le = l.GetEnumerator();
 
            while (le.MoveNext())
            {
                bool isModified = false;
 
                AxSecurityRole r = diskMetadataProvider.SecurityRoles.Read(le.Current);
                KeyedObjectCollection<AxSecurityPrivilegeReference> privs = r.Privileges;
 
                isModified = removeNode(r, privs, "JADCCDelayCaptureBatchProcess") || isModified;
                isModified = removeNode(r, privs, "ProfitAccountStatistics_CustItemGenerate") || isModified;
                isModified = removeNode(r, privs, "CCMOrderPadLoginManagementMaintain") || isModified;
 
                if (isModified)
                {
                    ModelSaveInfo model = diskMetadataProvider.ModelManifest.ConstructSaveInfo(diskMetadataProvider.ModelManifest.GetMetadataReferenceFromObject("JADOperation", "AxSecurityRole", r.Name).ModelReference);
                    diskMetadataProvider.SecurityRoles.Update(r, model);
                }
 
            }
 
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }
}

And this is all that you require for modifying D365FO metadata using reflection.

You can find some other use cases of doing metadata reflection in previous blog posts as well: