RSS

Detailed steps to creating your own useful AX custom best practice check and custom attribute! Quick & Dirty

24 Sep

See More : http://www.alexondax.com/2014/05/walkthrough-detailed-steps-to-creating_4855.html

In this walkthrough will be showing you both directly and indirectly how to:

  • Create a custom attribute
  • Create a custom Best Practice Check
  • Reflect on the AOT to see if an object has that attribute

  • Throw best practice warnings in the compiler
  • And more!

Node/Disclaimer:

This is proof of concept code which is demonstrating these concepts in the simplest way, but you should use these concepts and refactor them to follow best practices such as using labels, EDTs, etc.  You should also create new methods for commonly used blocks of code.  You can take these concepts and expand them to real-world uses too.

Create the custom attribute:

Create a class and name it “MyCompanyAttribute” and extend SysAttribute.  Add a member variable “int feature;” to the classDeclaration.

class MyCompanyAttribute extends SysAttribute
{
    int feature;
}

Add an accessor method to get the feature value.

public int feature()
{
    return feature;
}

Important!

Create the new() method. This method is important to assign the variables, and XML documentation is crucial here too for intellisense to display to developers.  Note that I default “feature = 0” in the arguments so that it will make this parameter optional.

Intellisense will look like this:

/// <summary>
/// Initializes an instance of the <c>MyCompanyAttribute</c> class
/// </summary>
/// <param name="_feature">
/// Internal company feature number for customization tracking
/// </param>
/// <remarks>
/// This attribute should be used on custom methods added to base classes
/// </remarks>
public void new(int _feature = 0)
{
    super();

    feature = _feature;
}

Custom attribute done!

Add Best Practice Check and hook:

The class `\Classes\SysBPCheckMemberFunction` is what checks all member functions.  I will be limiting the code to strictly only checking class member functions in the CUS+ layer.

First create your new method that does the work:

protected boolean checkMyCompanyAttribute()
{
    boolean         ret = true;
    UtilElements    utilElements;

    switch (SysDictMethod.utilElementType())
    {
        case UtilElementType::ClassInstanceMethod:
        case UtilElementType::ClassStaticMethod:
            // Find the lowest layer this object exists in
            select firstOnly RecId, UtilLevel from utilElements
                order by UtilLevel asc
                where utilElements.parentId     == SysDictMethod.parentId()
                   && utilElements.recordType   == sysDictMethod.utilElementType()
                   && utilElements.name         == sysDictMethod.name();

            // If the lowest layer is CUS+ then we want our custom checks enforced
            if (utilElements.utilLevel >= UtilEntryLevel::cus)
            {
                // Now check if the attribute is not decorating the method
                if (SysDictMethod.getAttribute(attributeStr(MyCompanyAttribute)) == null)
                {
                    // Developer has failed the BP check!  Let them know
                    ret = false;

                    // This is what puts the BP error in the compiler window.
                    SysBPCheck.addError(0, 1, 1, 'MyCompanyAttribute: Missing custom [MyCompanyAttribute] on custom CUS+ layer method.');
                }
            }

            break;

        default:
            ret = true;
    }

    return ret;
}

Then in `\Classes\SysBPCheckMemberFunction\check` this is where you put your hook to call your BP check.

MS Best Practice Note: If you were to do this for a customer or in a live system, you should really create an EDT(s) and parameter(s) on `\Data Dictionary\Tables\SysBPParameters` then add them to `\Forms\SysBPSetup` so that users can enable/disable them.

Final Steps to get it picked up and active:

Turn on Best Practice Checks if you haven’t already! See http://msdn.microsoft.com/en-us/library/cc967377(v=ax.50).aspx for detailed directions or the abbreviated directions are just set your compiler to “Level 4”

You may need to recompile `SysBPCheckMemberFunction` or better yet just compile forward `\Classes\SysBPCheckBase`.

You may need to close/reopen your compiler and/or client too.  When the compiler window is opened, it builds various maps.

Results:

It works!  It should error on your new custom method.

You will notice a purple underline on the method too:

Let’s add our attribute and recompile the class (not just the method) and resolve the BP check:

Closing Notes:

In my code, I used error code 0, which doesn’t appear to be used by Microsoft.  You should really define a new macro definition and error code in `\Macros\SysBPCheck`.

The error code appears to be used for two things.

  1. Obvious: Provide an easy error code # to look-up instead of searching the error string, especially if the string is truly something like `Error on %1` where the string changes depending on the code.
  2. Not so obvious: `\Classes\SysBPCheck` builds an ignoreMap(ErrorCode[int], Paths[Set of strings]) and the error code is the key.
I recommend prefixing your error message with something (like “Alex:” )to clearly identify your BP check as custom, especially if your BP check has a bug or scenario you hadn’t anticipated and is mistakenly being thrown.
A comment on reusing the same error code.  If you throw the same BP error on the same method/line/column, it will only take the last one.  The same error can’t happen twice on the same method/line/column logically so this makes sense.  So because of this, if you use (0,1,1) for the first three parameters and just change the error message, sometimes when you intend to display multiple messages, only one will appear.

Ignore rules: 

If you have some specific objects you always want excluded, you can add them to `\Macros\SysBPCheckIgnore` and make sure your error code is added in `\Macros\SysBPCheck`.
Alternatively, you can just create a custom Set of paths then union them to the ignoreMap created in `\Classes\SysBPCheck\initIgnoreMap`.
Advertisements
 
Leave a comment

Posted by on September 24, 2015 in Uncategorized

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
All About Dynamics 365

Dynamics 365, D365, Implementor

Syed Rafay Ali

This blog contains information about Functional techniques and guidelines in Microsoft Dynamics AX, including tips, tricks, tutorials, tools and upcoming news enhancement in Microsoft Dynamics Ax

Philippsen's Blog

Everyday findings in my world of .net and related stuff

Microsoft Dynamics AX

A great WordPress.com site

Finite Minds

Adventures in IoT

Dynamics Ax

Technical Knowledge

timsaxblog

A blog about implementing Microsoft Dynamics AX and Dynamics 365 for Operations

Microsoft Dynamics 365 Blog

Strat your organization's digital translation with Dynamics 365, A Blog by Sandeep Chaudhury

DEVSerra - Dynamics AX development blog

Your official Microsoft Dynamics AX blog.

OrganicAX

Discovering Dynamics

AX

A blog by Hai Nguyen

Learn Dynamics Ax with Johnkrish

Live as if you were to die tomorrow. Learn as if you were to live forever - Mahatma Gandhi ****** The more I learn, the less I know - Albert Einstein

Twisted Untwirled

Just another WordPress.com site

ramdynamicsax

Just another WordPress.com site

guyterry's Dynamics AX blog

Just another Dynamics AX blog

%d bloggers like this: