When Microsoft releases new versions of Microsoft Dynamics 365 Finance and Operations, a lot of enhancements are listed on a workspace called Feature Management, where you can review the new features and decide which one would need to be enabled for your organization. The features can be a new module, new additions, enhancement of an existing feature, and performance improvements. In this blog, I will answer a question: “Can you add features as an ISV or partner to Feature Management?”. Continue reading if you want to know the answer.

Feature management

Let’s first briefly outline the current Feature management solution provided by Microsoft. When starting the page, you will have visibility on all available features that can be reviewed and enabled. You can view the status and can check which features are turned on mandatory or by default.

When you select a feature, you get a small description and a link to an external site with more information. One thing you need to be aware of is that some features can’t be turned off when enabled or have dependencies on other features. All important details can be read on the right panel next to the overview.

Technical background

Now let’s focus on the question in the title. Are we able to add features as an ISV or partner? The answer is: Yes. I will explain how this is built by Microsoft. The page shows data from a table with feature metadata. This table is populated by classes with a specific pattern. The declaration always looks like this:

[ExportAttribute(identifierStr(Microsoft.Dynamics.ApplicationPlatform.FeatureExposure.IFeatureMetadata))]
[Microsoft.Dynamics.BusinessPlatform.SharedTypes.InternalUseOnlyAttribute]
internal final class AssetLeaseAssetLeasingEnableFeature implements IFeatureMetadata

The class commonly has functions like:

  • instance
  • label
  • module
  • summary
  • learnMoreURL
  • isEnabledByDefault
  • canDisable

In the AOT, you can find these classes as they commonly have a suffix with the word Feature. In addition, there can be some x++ code to check for e.g., pre-requisites or if the feature is enabled by an administrator. You can even add coding to populate some data in tables that would be required for the feature to function correctly. E.g., when Microsoft added features for default saved view, upon enabling, it did add records to the table containing all saved views.

During an installation of a deployable package, a job will run to refresh the list with features. This loops the classes and will populate the metadata table for feature management. When the feature is listed, it will by default not know what parts of the application belong to the specific feature. With additional coding, menu items or specific form controls can be hidden. Some features, like performance enhancements, are not visible, and then in coding, a switch is applied to run the legacy or the new enhanced coding.

To implement something yourself, you would need to think about what to show/hide and where to add some coding. This could be form-specific logic or other classes containing that logic.

Example

Several years ago, I shared a small feature called Session language. With this utility, a user can quickly change the language of the Dynamics 365 session without changing the default language on the User options or manipulating the Dynamics URL where he might not know the abbreviation for the language to use. I took the coding from my archive and added two classes. One to populate the feature in the metadata and another one to show or hide the feature in the System settings menu.

The class for feature metadata looks like this.

using System.ComponentModel.Composition;
using Microsoft.Dynamics.ApplicationPlatform.FeatureExposure;

/// <summary>
/// The <c>DynPed_SessionLanguageFeature</c> class defines the feature, when enabled, will allow user to switch the session language.
/// </summary>
[ExportAttribute(identifierStr(Microsoft.Dynamics.ApplicationPlatform.FeatureExposure.IFeatureMetadata))]
[Microsoft.Dynamics.BusinessPlatform.SharedTypes.InternalUseOnlyAttribute]
internal final class DynPed_SessionLanguageFeature implements IFeatureMetadata
{
    private static DynPed_SessionLanguageFeature instance = new DynPed_SessionLanguageFeature();

    /// <summary>
    /// Gets the session language feature instance
    /// </summary>
    /// <returns>The session language feature instance</returns>
    [Hookable(false)]
    public static DynPed_SessionLanguageFeature instance()
    {
        return DynPed_SessionLanguageFeature::instance;
    }

    [Hookable(false)]
    public FeatureLabelId label()
    {
        return literalStr("@DynPed_SessLang:SessionLanguage");
    }

    [Hookable(false)]
    public int module()
    {
        return FeatureModuleV0::ISV;
    }

    [Hookable(false)]
    public FeatureLabelId summary()
    {
        return literalStr("@DynPed_SessLang:SessionLanguageFeatureSummary");
    }

    [Hookable(false)]
    public WebSiteURL learnMoreUrl()
    {
        return 'https://dynamicspedia.com/2020/01/session-language/';
    }

    [Hookable(false)]
    public boolean isEnabledByDefault()
    {
        return false;
    }

    [Hookable(false)]
    public boolean canDisable()
    {
        return true;
    }

    /// <summary>
    /// Determines whether the feature is enabled.
    /// </summary>
    /// <returns>
    /// Returns true if the feature in Feature Management is enabled; otherwise, false.
    /// </returns>
    [Hookable(false)]
    public static boolean isEnabled()
    {
        return Dynamics.AX.Application.FeatureStateProvider::isFeatureEnabled(DynPed_SessionLanguageFeature::instance());
    }

}

Usually, the learn more URL refers to a specific page on Microsoft Learn. In this case, I used the URL of the blog where I explained about this feature.
The feature module is set to ISV in my example which has the label 3rd party solution. The enum FeatureModuleV0 is not extensible. I was not able to add a new module as part of an extension.

The second class is managing if the menu item in the system settings menu should be visible or not, based on the feature state. I did take the class ExpenseFeatureManagementShowHideMenuItems as an example of how to show or hide menu items in menus on runtime using x++. It is interesting to know that there is an option to manage the visibility of menu items and tiles in menus via

/// <summary>
/// The <c>DynPed_SessionLanguageShowHideMenuItem</c> class is used to enable or disable the menu item for the session language in the settings menu.
/// </summary>
internal final class DynPed_SessionLanguageShowHideMenuItem
{
    /// <summary>
    /// Determines the menu item visibility based on feature management.
    /// </summary>
    /// <param name = "_rootMenu">Root menu.</param>
    /// <param name = "_subMenu">Sub menu.</param>
    /// <param name = "_subMenuVisibility">Whether or not the submenu should be visible.</param>
    /// <remarks>This will only hide the individual menu items if they are contained in a group that we will also be hiding.</remarks>
    [SubscribesTo(classstr(SysMenuNavigationObjectFactory), staticdelegatestr(SysMenuNavigationObjectFactory, checkAddSubMenuDelegate))]
    public static void menuItemVisibilityHandler(SysDictMenu _rootMenu, SysDictMenu _subMenu, SysBoxedBoolean _subMenuVisibility)
    {
        if (_subMenu.isMenuItem())
        {
            var metaElement = _subMenu.GetMenuItemMetaElement();
            if (metaElement != null)
            {
                if (metaElement.Name == menuItemDisplayStr(DynPed_SessionLanguagePane))
                {
                    _subMenuVisibility.value = DynPed_SessionLanguageFeature::isEnabled();
                }
            }
        }
    }

}

I didn’t change any other logic or contents from my previous version of the session language feature, apart from resolving some best-practice warnings. With these two classes, the session languages feature will be embedded in feature management. Note that the feature will initially not be visible in a development environment when you build the models or solution. On feature management, you must then click the button Check for updates. This will update the metadata table with new information, like a deployment is also executing.

The list with features on the tab New shows all features for the latest date when a feature was added. You will also get a notification that 1 feature has been added. When you install a Microsoft update, you might have e.g. 47 new features as a summary in the notification center.

When enabling the feature, you should refresh the browser session to get the cache refreshed and the feature is then really activated for all users.

In this example, only the menu item Session language was visible or not depending on the feature state. When required, the feature, with the current settings in the feature class can still be disabled. You can change this behavior (with a valid reason) in the feature class by changing the return value for the method canDisable.

Conclusion

Despite it is possible, I don’t think that Feature management is fully ready to support ISV or partner solutions. My main concern here is that the Module enumerarion is not extensible. You would like to mention your own module name instead of a generic text 3rd party module. In addition, a column mentioning the provider would be helpful. Then it would be possible to search for specific Microsoft updates or e.g. updates from a specific ISV vendor.

When you would decide to implement your features as part of solution management, be aware that this is a global setting. Feature management is not replacing parameter forms where you can e.g. determine whether to allow for duplicate voucher numbers or not. In addition, feature management is also not replacing the configuration/license keys where you also can manage which parts of the application are not applicable to your organization.

Feature management is intended to postpone activating some features, so customers would get time to investigate the feature and its impact on their implementations.

There is more…

There is more to explore on Feature management. Sometimes it is not clear, even not with the documentation, about the exact purpose of a feature. In such cases, I usually take a look under the hood to check it out. My next blog will show an example of how you can reverse engineer a specific feature. I’m preparing that blog in collaboration with Hylke Britsma, also a Microsoft MVP from the Netherlands.



I do hope you liked this post and will add value for you in your daily work as a professional. If you have related questions or feedback, don’t hesitate to use the Comment feature below.


That’s all for now. Till next time!

2 replies
  1. mx_be
    mx_be says:

    Hi Andre,
    thanks for the good description, I enjoyed reading that!
    We, as an ISV, are currently faced with the decision to either design our own feature management, or to bring some new functions into the standard feature management via a special way. I think it’s a pity that there is no new information from the product manufacturer if and when the standard feature management will be opened for ISVs. Maybe this will change and we will get more information.

    Thank you!f

    Reply
    • André Arnaud de Calavon
      André Arnaud de Calavon says:

      Thanks for your comment. When I checked the options, I thought is was not suitable as you would like to distinguish yourself from other ISVs. For that purpose, you would indeed like to bring new functions, but other ISVs might implement similar changes. Then it can become messy.

      Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.