Mastering Microsoft Dynamics AX 2012 R3 Programming

2.5 (2 reviews total)
By Simon Buxton , Mat Fergusson
  • Instant online access to over 8,000+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Preparing Our Solution

About this book

Due to its interesting capabilities such as finance and supply chain management, business intelligence and reporting, project management, and so on, Microsoft Dynamics is one of the most widely used solutions adopted by many organizations across the globe. This book is a step-by-step tutorial that covers elements from the initial design through to development. Each concept is fully explained and demonstrated by the creation of a real-world project. You will learn some really useful, advanced development techniques such as extending your code with metadata and exception handling.

This book is an invaluable tutorial if you are moving from another ERP system or language, or if you are a technical consultant with a desire to create efficient functional designs and business solutions.

Publication date:
June 2015
Publisher
Packt
Pages
478
ISBN
9781782176015

 

Chapter 1. Preparing Our Solution

Dynamics AX provides one of the best development environments of any ERP product. It is often easy to forget that the purpose of this environment is to create or extend functionality in order to satisfy a business requirement. The purpose of this chapter is to provide a short refresher on some of the core concepts and the preparation work required, before we start cutting code to put us on the right track to develop or extend functionality in Dynamics AX. This will enable your solutions to be maintainable and extendable, and minimize the impact on future updates and upgrades.

This chapter does not cover the installation and configuration of the required environments; it is assumed that this has already been done. We assume that our development environment has the AX client, management tools, and Visual Studio Professional 2013 installed. If you are using a version prior to cumulative update 8 (CU8), you will need to use Visual Studio 2010 Professional.

If we have to use Team Foundation Server (TFS), each developer must have their own development environment. Typically, we will have a virtual server as a single box AX installation.

In this chapter, we will cover the following topics:

  • The technical architecture of a solution

  • Minimizing the footprint of customizations

  • Selecting the appropriate layer for our solution

  • Creating the models

  • Creating a label file

  • Configuring source control

  • Creating a project

  • Setting up a default project and model

  • Designing the technical solution

  • Designing test plans

 

The technical architecture of a solution


In the first part of this chapter, we will briefly cover some key topics to refresh our memory. We will then cover some areas that we will expand on as we progress through the chapters. If you want to read in more detail about the technical infrastructure, the MorphX IDE, and development practices and patterns, refer to Appendix A, Efficient Design and Development with Microsoft Dynamics AX.

A good design is just as relevant to small change requests as it is for larger development. It has many attributes; some key points to consider are as follows:

  • Configurable: As much of the decision making as possible should be stored in configuration and parameter tables. It may take longer, but it will save time when the development goes through integration testing.

  • Extendable: The solution (no matter how small) should be designed such that it can be extended without rewriting. Using patterns can help with this.

  • Design around standard patterns: This helps avoid reinventing the wheel and ensures a higher quality design that is more consistent. The solution we write should look and feel like any other part of AX. This means less training and better adoption by our users.

  • Validate the design: This should be done against the requirement before the work on the design commences. In some cases, it is appropriate to prototype the solution.

  • Use the advanced features of AX appropriately: Just because a cool feature exists, it doesn't mean that it should be used in this case.

  • Configuration and parameter tables should be rule-based: For example, a property used to determine which mode of delivery is urgent is limiting. It implies that there can only be one urgent delivery mode.

  • Minimize changes to standard code: The more standard code we change, the more work is required to maintain the system in terms of updates and upgrades. We will discuss minimizing this footprint in the next section.

Most of the functionality that we write in AX (a new solution or customization of an existing functionality) is data-based. We use forms to create, maintain, and view this data, tables to store and validate this data, and classes to act upon it.

Data structures

The first part to design is the data structures. Even though these may evolve, a lot of attention is required here. A simple analogy would be to compare this to building a house; you can change the furniture, even add a room, but you cannot add a basement garage.

There is some guidance to be found here, that is, the structure will normally fit into an existing pattern that is already being used by AX. We normally expect to have the following types of tables in our solution:

  • Parameter: This is a single record table that typically contains the table's defaults and other behavioral properties, such as the default printer settings.

  • Group: An example of this can be the customer group or delivery mode tables. They can act as lookup values, or even control functionality. For example, we may create a table that contains a user's default label printer.

    Tip

    When you find yourself creating multiple fields of the same type (for example, the Urgent delivery method, Normal delivery method, and Low priority delivery method fields), they should be recorded in a table with a reference (enumerated type) so that you can identify them in code.

  • Main: These are the master data tables, such as items and customers.

  • Worksheet header and Worksheet line: These are the standard document entry tables, such as the sales order table and lines, where the dataset has a header and lines.

  • Worksheet: This is a table used to enter data that is later processed in some way. This is not very common in AX as most documents have both a header and lines.

  • Transaction header and Transaction lines: These are the result of the worksheet after posting or committing, such as the sales invoice header and sales invoice lines.

  • Transaction: This is the table where the result of posting is a single-level transaction record. The stock transaction table called InventTrans is an example, which is viewed as a list of stock transactions.

Note

The preceding types are actually set as a property on the table when it is created, enforcing the pattern further.

During the course of this book, we will be writing a solution based on a hypothetical case of a fleet management system as Contoso's internal development team. Based on the previous guidance, we can take the following simple requirement and quickly turn it into a data structure: we require the ability to view and maintain records of vehicles and their utilization.

From this, we can see that we will need to store a list of vehicles, probably of varying types, and then a record of their utilization will be attached to each vehicle. This leads us to the following structure:

Table type

Example table name

Description

Parameter

ConFMSParameters

The main parameters

Group

ConFMSVehicleGroup

A list of vehicle types

Main

ConFMSVehicleTable

A list of vehicles

Transaction

ConFMSVehicleTrans

The utilization records

In this case, little thought was required as the requirement fits nicely into the standard AX patterns.

The naming was also straightforward: the organization's prefix is Con, the module's prefix is FMS, and the rest of the name comes from the entity name and the table type. You will see this type of naming throughout AX. As far as possible, we should be able to understand from the name alone what it is, what it does, how it does it, and why it does what it does.

The user interface

The next part of the structure is the user interface, where we again have a set of templates that suit most circumstances:

  • List page: This is the main entry point to both the main tables and worksheet tables. The list page offers the ability to search and act upon the data. You can also open a details form from list pages that allows the record to be edited or a new entry to be created. An example can be found by navigating to Forms | CustTableListPage.

  • Details form, master: This is designed to allow the maintenance of master data, such as customers and items. These are not entry points, but are opened from a related record or the list page. We sometimes use this form type to create data, but we typically use a specific creation form for this. An example can be found by navigating to Forms | CustTable.

  • Details form, transaction: This is intended for the maintenance of worksheet tables, such as the sales order form. An example of this can be found by navigating to Forms | SalesTable. The term "transaction" may be confusing here; it is not related to the TableGroup property of the table.

  • Simple list: This is useful for group and transaction tables that are a simple list of records with only a small number of fields to present. An example of this can be found by navigating to Forms | CustClassificationGroup.

  • Simple list, details: This is where the group table has many fields that are better arranged in groups of fields. There is still a list element, but there is a pane that allows for easier entry of data. An example of this can be found by navigating to Forms | DeliveryMode.

  • Table of contents: This template is used for parameter forms. An example of this can be found by navigating to Forms | CustParameters.

  • Dialog: These forms follow a style design to be used as a popup to gather some information and return it to the caller. A form used to create data is likely to use this template as we enter data and then ask AX to create the record once complete.

  • Drop dialog: These appear as if they drop down from the calling button, and are typically used to perform an action using the current record. They are designed to display a small number of form controls, which the user will update as required before pressing OK. The following screenshot shows this:

Note

The preceding templates are available for us to choose from when we create a form. Using these templates further assists us in creating a user interface consistent with AX.

Based on the preceding templates, we can create the following forms for our example requirement:

  • Table of contents: ConFMSParameters

  • Simple list, details: ConFMSVehicleGroup

  • List page: ConFMSVehicleTableListPage

  • Details form, master: ConFMSVehicleTable

  • Simple list: ConFMSVehicleTrans

We normally name forms after the table they act on, except for list pages. The last example does not really have a true template; the simple list is the closest. The data structures and forms are taken directly from how other parts of AX behave. This should always be a design goal as it ensures that our users' incumbent knowledge of AX is used, reducing the time needed to learn the new feature and minimizing errors.

Application logic

Classes are used to store the main business logic. They are often used to handle user interface and table events as well. This allows the code to be reused and extended more easily.

The other key point is that we should also consider that we may want our solution to be available on mobile devices, and a careful thought about how we write the logic can make this much easier.

Classes in AX can be deployed as custom services that are consumed as WCF services in mobile or other Windows applications. This means that the logic should be simple to access, and have business logic in distinct classes, allowing the logic to be reused safely.

For example, we have a table with a status field that performs some validation and other events. We would write this in the data contract and service class pattern—a data contract to store the data to be acted upon and a service class to process the change. This can be used in a dialog form with the AX client or exposed as a service, allowing a mobile application to set the status.

 

Minimizing the footprint of changes


The footprint we make on existing objects is a key consideration when it comes to solution maintainability and the associated costs.

Microsoft has made key investments in the development environment in order to make it easier to write code in such a way that it sits alongside another party's solution. The advantage for Microsoft is that their customers can adopt multiple solutions or add-ons from ISVs with minimum effort.

Prior to AX 2012, this effort would have involved merging code from different partners and additional effort would have been required to ensure that a hotfix from one organization did not regress code in another add-on.

The next sections will highlight the practices and technologies that accomplish this.

Where to make the change

We are often asked to make changes to AX that require standard objects to be modified; often, the difficult decision is about where the change is to be made.

Firstly, we should consider how the code is structured by taking the example of a form that acts upon a table. Tables are structured into fields, field groups, indexes, relations, delete actions (for example, cascading the deletion to child tables), and methods. Forms are structured into form-level methods, data sources (a reference to a table), and controls. A request might be, "Can we make the vehicle field on the transport form mandatory?"

This is possible; the form control does have this property, as do the data source field and the equivalent field on the table—so, which of these to use? The answer is always as high in the stack as possible. The requirement is that the table always has this particular field filled in, so wherever this field is added, it should be mandatory.

The same pattern applies to code changes—always at the highest level and in this order: class, table, form data source field/method, form control.

Note

Making changes to form controls is very rarely required, and should be considered as a deviation from best practices.

Even hiding controls on forms should be handled in a method (which is usually called enableControls), as this makes the change more obvious and much easier to read, extend, and reuse.

The use of field groups

We may already use field groups, and it is best practice to do so. It may seem strange at first that we are creating what are essentially UI components in the data layer, but this pays off in terms of consistent UI and reduced footprint on standard AX. Forms dynamically display the fields that are in that field group; by adding a new field to the appropriate field group, the forms magically display this new field.

The reason this reduces footprint is because we are making one change that affects all forms that refer to the field group, and doesn't affect the form when applying updates.

Eventing

Eventing is a new key feature in AX 2012 that, along with models, is a key enabler for ISVs to write add-ons for AX.

Event subscription

This technology allows you to subscribe to an event in AX. So, instead of modifying the method, we simply subscribe to it as a pre- or post-event. We can then perform our logic elsewhere in an X++ or a .NET assembly, and even modify method parameters and return values.

This subscription is not a modification to the source method. Therefore, a method can have subscriptions in several different models in the same layer.

Delegates

Delegates are empty method stubs to which we subscribe. They are created by the original author and called from within their code. This is done so that you can subscribe to events that happen within a method without modifying a method.

For example, the following lines of code would be a delegate written by an ISV (Axp is the prefix used by this ISV):

delegate void weightCaptured(AxpWeighTicketContract _contract)
{
}

The ISV will then call this delegate at the appropriate time with the data contract. By subscribing to this delegate, you can handle the event and perform the necessary tasks with the supplier contract. This provides a hook into the supplied solution without modifying it. For more information about the guidelines on delegates, visit http://msdn.microsoft.com/en-us/library/gg879953.aspx.

Extending a class

Another method of modifying behavior with a minimal footprint is to extend the class. This should be done only if you cannot perform the task through an event subscription.

The pattern is implemented with the following steps:

  1. Create a new class and use the extends keyword to extend the class you need to change.

  2. Override the method you wish to change.

  3. Modify the construct method on the base class so that it constructs your class based on the criteria you want.

Table-level form events

The table has several events that happen based on form events. In this example for the modified event, the mechanism is conceptualized as follows:

  • A data bound field's modified event will call the data source field's modified method

  • The bound data source field's modified event will call the table's modifiedField event with the field ID of the field being modified

The table's modified event is normally a large switch statement based on the field ID parameter with a case for each handled field. To modify this, we can simply add a case for our new field or change the behavior of an existing case.

In this situation, we should subscribe to the modifiedField method, but another option would be to create a new method with the same profile. This is preferable if we are the end-user organization, but is essential for VARs and ISVs. This is done by copying the method header. Let's take a look at the following example:

public void modifiedField(FieldId _fieldId)

We can then create a new method, as follows:

public void conModifiedField(FieldId _fieldId)

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

We can then create a switch statement to handle the fields we need to in this new method. In order to call this new method, we can then add a call to our new method in the original modifiedField method:

public void modifiedField(FieldId _fieldId)
{
    super(_fieldId);
    switch (_fieldId)
    {
        case fieldNum(<TableName>, <FieldName>):
            // code
            break;
    }
    // Con Var modification by SB 2014/06/09 handle custom fields
    this.conModifiedField(_fieldId);
}
 

Selecting the appropriate layer for our solution


This choice of layer is normally straightforward. As an ISV, we will use the ISV layer; as a VAR, the VAR layer; and so on.

We can sometimes choose, as the end user between the higher layers, CUS and USR. It does not normally matter which, as long as we stick to it. Incorporating more layers adds to the maintenance cost.

The main reason for using both CUS and USR is when we (as an end user organization) have multiple installations of AX that share a common base application. We would manage the CUS layer centrally, and each installation will be responsible for their installation-specific customizations in the USR layer.

The layer is selected in the AX Configuration Utility. To change the current layer, follow these steps:

  1. Open Microsoft Dynamics AX 2012 Configuration Utility. This is accessed from the Administrative Tools Windows program group.

  2. Select the desired configuration from the Configuration drop-down list and select the Developer tab.

  3. Select the appropriate layer from the Application object layer to open drop-down list.

  4. If the layer is not usr, you will need to enter the development license code in the field Development license code, and again in Confirm license code.

  5. Press OK.

When we open the AX client the next time, the configured layer will be used.

 

Configuring source control


In this section, we will first configure the system to use MorphX VCS, and then reconfigure it to use Team Foundation Services.

Configuring AX to use MorphX VCS

If we are using MorphX VCS, which was designed for one to five developers, we will all be working on the same environment. This is called shared development.

MorphX VCS is set up within the MorphX IDE, as follows:

  1. Navigate to the IDE (Ctrl + D).

  2. From the main menu, go to Version Control | Version Control Parameters (or press Ctrl + Shift + V).

  3. Configure the form as shown in the following screenshot:

  4. Press OK.

We can then configure the system settings for additional control over the VCS settings. This is covered towards the end of this section.

Configuring AX to use Team Foundation Services

In order to use TFS, we need access to a TFS server. This can be installed on premise, or we can use Visual Studio Online. For more information on Visual Studio Online, refer to http://www.visualstudio.com/en-us/products/what-is-visual-studio-online-vs.aspx.

If AX is cumulative update 8 or later, you will need Visual Studio 2013 professional or a higher edition. Ensure that you have started Visual Studio once and signed in with your Microsoft account.

Using Visual Studio Online with AX CU7 or prior

If you are using cumulative update 7 (CU7) or prior versions, AX will not support Visual Studio 2013, which makes it incompatible with Visual Studio Online as this always uses the latest release. If we try to use Visual Studio Online, it will not be able to authenticate and we will be denied access to the online service.

In order to solve this, we need to install Microsoft Visual Studio Team Explorer 2013, which is a free download available at http://www.visualstudio.com/downloads/download-visual-studio-vs. Once this is installed, you need to start Visual Studio and log in with your Microsoft account. Team Explorer installs the Visual Studio 2013 shell in order to make it available for use with AX. This is where you manage the connection to Visual Studio Online.

Prior to Visual Studio 2010, we had to install Microsoft Visual Studio Team Foundation Server 2013 MSSCCI provider (MSSCCI). Further information on this is available at http://msdn.microsoft.com/en-us/library/dd997788.aspx#msscci. This needs to be installed in order for AX (prior to CU8) to connect to the latest TFS release.

Note

The Visual Studio Online service is a great way to gain access to TFS, and is currently free for up to five users.

Creating a new TFS project using Visual Studio Online

In this example, we will use Visual Studio Online. Registration is free but a Microsoft account is required to access the service. You will be given a portal URL that reads something such as https://<yourorganisation>.visualstudio.com.

Once the required steps have been done, we can create our new TFS project, as described in the following steps:

  1. Open your Visual Studio Online portal.

  2. Under Recent projects and teams, select New. This opens the following form:

  3. Configure the form as required. In our example, we will use 6015GettingStarted as the project name.

  4. Press Create project. After a short time, this message will be displayed:

  5. Click on Navigate to project.

  6. This opens the new project. In this form, we should add the team members using their Microsoft account.

  7. Once the team members are added, we can move on to configuring AX. The next step is done by each developer.

  8. Create a folder in your local hard drive for the local files. For example, C:\Projects\VCS\AX\6015GettingStarted.

    Note

    The folder must be specific to AX and should be named the same as the TFS project name.

Configuring AX version control parameters to connect to TFS

The following steps complete the configuration:

  1. Open the AX IDE and then the Version Control Parameters form.

  2. Configure the General tab, as follows:

    Note

    The Repository folder is the structure below our project folder.

  3. When Version control system is changed to Team Foundation Server, a Team Foundation Server tab appears on the left table of contents pane. Select this tab.

  4. Configure Team Foundation Server options as follows:

    Team Foundation Server URL

    This is your local TFS address or your Visual Studio Online URL, for example, https://<yourorganisation>.visualstudio.com/DefaultCollection.

    Team Foundation project name

    This is the project name we created in TFS; in this case, 6015GettingStarted.

    Branch folder

    We do not recommend branching at this stage. Enter Trunk in this case.

    Application root folder

    This is the folder name we created for the project, for example, 6015GettingStarted.

  5. Press OK.

  6. AX will show the Sign-In to Team Foundation Services dialog, as shown here:

  7. Complete the form with the same account details that you use to access the portal.

  8. If successful, AX will show the following message:

    Pending add on C:\Projects\VCS\AX\6015GettingStarted\Definition\VCSDef.xml with status Getting

Troubleshooting

The most common error is as follows:

This has the following possible reasons:

  • The URL was entered incorrectly; most likely, DefaultCollection was misspelt or missing

  • MSSCCI was not installed—CU7 or prior releases of AX

  • You do not actually have permission

If the URL is incorrect or you have no access to the Internet, the following message is displayed: Team Foundation services are not available from server https://badnameurl.visualstudio.com/defaultcollection.

The best way to debug this is to open the URL (copied from the settings form) to a browser. If this works, try connecting to TFS through Visual Studio 2013, as shown in the following steps:

  1. Open Visual Studio 2013 (or Team Explorer if using CU7 or prior releases).

  2. Navigate to TEAM | Connect to Team Foundation Server.

  3. In the Connect to Team Project dialog, click on Servers….

  4. In the Add/Remove Team Foundation Server dialog, click on Add….

  5. Configure the Add Team Foundation Server dialog, as shown in the following screenshot:

  6. Press OK.

  7. Visual Studio will now ask you to log in. Sign in using the credentials you used to access the Visual Studio portal.

  8. Close the Add/Remove Team Foundation Server dialog.

  9. The Connect to Team Project will now show the team project collections, but we can simply close this as we have completed the required authentication to Visual Studio Online.

  10. Open the AX client again, and try the configuration again.

We can now add the elements we create or modify to source control. Refer to Appendix B, Using Version Control, for more information on using source control.

 

Creating the models


The models required depend on your organization's requirements, and these were discussed in the previous chapter. In this section, we will create the models based on our Fleet Management System, from a customer or end user perspective.

Models should also include your prefix. In this case, we will use the Con prefix for Contoso. We will create our models in the USR layer, as explained later in this section.

ISV models

ISVs will normally have a base model that contains shared code between all models, and a model per add-on or vertical solution. Some care is required in ensuring that there isn't a circular dependency chain between models; that is, both reference each other's models, requiring the installation to have special instructions.

Following the naming convention discussed in the previous chapter of prefixing elements—an ISV with the Axp prefix and an add-on named Documental—they can name the model AxpDocumental.

VAR models

If we are a VAR building a solution to customer-specific requirements, we will have three models: one for the actual modifications, another for changes to security, and the third for the labels. For example, if our prefix is Bcl and the customer is Contoso, we will have BclContoso, BclContosoLabels, and BclContosoSecurity.

Creating security in a separate model is not mandatory, but helps when implementing projects with the Sure Step methodology because it allows security to be worked on in separate streams.

Customer or end user models

If we are a global organization, with separate Dynamics AX installations, we may decide to develop a central application, which is then installed on each site. In this case, we will have three models placed in the CUS layer. For the Contoso example, we have ConGlobalApplication, ConGlobalLabels, and ConGlobalSecurity.

The most common scenario is to host Dynamics AX centrally, therefore having one application. The same three models are required, but this time in the USR layer: ConApplication, ConLabels, and ConSecurity.

It may make sense to place distinct sets of functionality in separate models, and this would certainly help in managing separate development streams. Over time, the models tend to develop cyclic dependencies, which require them to be merged in order to ensure that a complete set of code is deployed.

In our example, we will create a model for a specific functionality—our Fleet Management System—and it will make sense to hold it in a separate stream. However, it would be a particularly bad idea to hold each module's modifications in its own model.

Creating the models

Before we create the models, we must be in the correct layer; the USR layer in this case. The model creation is done by following these steps:

  1. Open the Dynamics AX Client, and open the development environment (Ctrl + D).

  2. From the main menu, go to Tools | Model management | Create model.

  3. Complete the Create model form as shown here:

    Field

    Description

    Model name

    This is the name of the model. It can contain spaces, but it is normally the same as the display name.

    Model Publisher

    Your organization or department.

    Layer

    The layer the model should be created in. This should be the current layer.

    Version

    The version of the model. This becomes part of the strong name of the model during signing.

    Model description

    Long description of the model. It is a good idea to link this to a functional or technical design document.

  4. Leave Set as current model checked and press OK.

An example of a completed Create model form is shown in the following screenshot:

If we have version control enabled for TFS, we will also ask for the Model repository folder. It will suggest, in our example C:\Projects\VCS\AX\6015GettingStarted\<Model folder>. Replace <Model folder> with the model name, as shown in the following screenshot:

Using the preceding instructions as a guide, we will need to create the following models. Usefully, AX will remember the previous information, so we only need to populate Model name and Model display name:

  • ConFleetManagement

  • ConLabels

  • ConFleetManagementSecurity

 

Creating a label file


Labels are not only a great feature of AX, giving an easy way to provide multilingual features, but are also required in order to comply with best practices. Labels should be placed in their own model, which we created earlier.

The label file is identified by three characters, and the list is global. The normal name is our prefix; for example, it could be CON for Contoso. DYN, AX, and DAX are particularly bad names as they may be used by Microsoft or an ISV at some point.

To create the label file, follow these steps:

  1. Change to the ConLabel model by going to Tools | Model management | Change current model.

  2. Ensure that the ConLabel model is shown in the lower status bar, as shown in the following screenshot:

    Note

    If this does not display, navigate to Tools | Options | Status bar and check Show current model.

  3. Go to Tools | Label | Label file wizard from the main menu.

  4. On the Add label file page, accept the defaults (only Create new label file ID is checked) and press Next.

  5. On the New label file ID page, enter the label file ID; in our example, it's CON. Pay attention to the warnings on this page!

  6. Press Next. On the Create the label files page, press Finish.

The AX Client will appear unresponsive for a short time while it creates the label file. Once the Label file wizard closes, the label file will exist in the AOT.

Navigate in the AOT to Label files. You will see the new label file, CON, as shown in the following screenshot:

 

Creating a project


We should have a project for each area of work, for example, one project for each business requirement document. This helps spread the workload across the team, which is ideally split in such a way that the same objects are not modified by different developers.

If we are using source control, the object (form, class, table, and so on) will be locked until checked back in. This can become very inefficient if, for example, we have two different developers working on sales order requirements.

The naming is important; a common structure is as follows:

<Prefix><Requirement Id><Description>

For example, if we are working on a requirement to credit history fact panes to the sales order, as identified in the requirement document 2.4.1, we may name the project BclFDD241_SalesOrderCreditHistoryFactPanes.

To create a new project, follow these steps:

  1. Change the model to ConFleetManagement.

  2. Open the project window (Ctrl + Shift + P)

  3. Right-click on the Shared node and go to New | Project.

  4. Press F2 to rename the project to ConFleetManagementSystem. We would normally include a reference number, which you may see referenced as a Functional Definition Document (FDD) or Technical Definition Document (TDD) reference.

  5. Open the project by double-clicking or pressing Enter.

  6. This opens a blank project, where we can create objects or drag from the AOT. However, we will create a structure similar to the AOT, as follows.

  7. Right click on the root ConFleetManagement node and go to New | Group.

    Note

    We can see many options in this list, one for each AOT object type. Creating objects directly in the root node can make it difficult to manage. Having them grouped is much better as the project grows.

  8. This will create a group object named Object1. Opening the Properties tab shows that this group can contain All AOT object types.

  9. Since we are copying the AOT structure, we should change ProjectGroupType to DataDictionary, and Name to Data Dictionary, as shown in the following screenshot:

  10. In the AOT, this node contains tables, so right-click on our new Data Dictionary node and select New | Group. This time set the ProjectGroupType property to Tables, and Name to Tables.

  11. Continue to create at least the following, as per the AOT structure:

    Tip

    The ProjectGroupType is the same as the AOT name, except for the Security subnodes. They are prefixed with Security.

Since creating the project structure can be time-consuming, it is a great idea to create a project called <prefix>ProjectTemplate. We simply duplicate (right-click and choose Duplicate from the context menu) the project and rename it each time we need a new project.

Note

All new objects must be manually added to source control; this includes projects. This is done by right-clicking on the project and selecting Add to Version Control.

 

Setting up the default project and model


AX will set the model to the default model whenever the client is opened. This will be USR Model if we are working in the USR layer. To avoid adding objects or changes to the wrong model, we can change this default. To do this, follow these steps:

  1. In the development environment's main menu, go to Tools | Options. This will open your user options.

  2. Select the Development tab and configure the form, as shown in the following screenshot:

  3. The key points on this form are as follows:

    Startup project

    The project AX will open by default. This can be useful when we work primarily in one project.

    Startup model

    The default model that AX will select when starting up. This is very important, and critical for users setting up security from the client (as the model is not obvious to them).

    Execute business operations in CIL

    Many events in AX, such as table events, will run automatically in IL (IL is the more common .NET term for this). This can cause confusion when we forget to generate the incremental CIL, especially when we don't configure the AX server to allow hot swapping of assemblies.

    During development, it is a good idea to uncheck this option and enable hot swapping of assemblies in the AX Server Configuration. Please see Hot-swapping of .NET assemblies in the AOS [AX 2012] at https://msdn.microsoft.com/en-us/library/hh538487.aspx.

 

Designing the technical solution


In most implementations, we have several roles involved in the solution design, build, and implementation. Our role is to design and develop a technical solution to a business requirement, and as discussed earlier, we will follow the design and build of a Fleet Management System.

The first steps in this are to analyze the business requirement and design a solution within Dynamics AX. This work will typically be led by a consultant, who will (in short) perform the following:

  • Match the business requirements to the AX functionality. The requirement may require new functionality or an extension to existing functionality.

  • Discuss the technical solution with a technical consultant/developer in order to design a solution that is feasible in AX in a suitable time frame.

  • Work through the solution with the solution architect to ensure that it fits in the overall solution design.

Create functional design documents. These will be signed by the customer stakeholders and process owners.

The consultant may propose table structures as parts of the functional design, but these are only to reinforce the requirement. The technical designer may find a more appropriate solution to this. The process is intended to leverage the skills of all parties in the solution delivery, allowing all parties to use their skills by abstracting the solution. Here is its summary:

  • The customer or process owner understands the process

  • The consultant is an expert in AX and focuses on the solution, creating a FDD

  • The solution architect validates the FDD against the solution design

  • The technical architect (or lead/analyst developer) creates the technical design while validating that it fits with the overall technical solution

These roles often merge, but there should always be a separation of business requirement definition and technical design definition. This freedom over the technical design does not mean we have total freedom over the technical solution. At all levels, it has to both match the original requirement and fit in with the overall solution. Just because it is technically cool does not mean it is appropriate. Our purpose is to create a technical solution to a business requirement.

We will evolve the design throughout this book, and the reason for each decision will be explained. It is important to understand and follow these design goals:

  • Upgrades and system maintainability: Minimize the footprint on standard AX.

  • Design for code reuse: This could span from creating a general framework to a useful static function on a global class.

  • Design for a service-oriented architecture: Always consider that your code might be used as a service or as part of a service. This paradigm also promotes code reuse.

  • Validate the design: Always validate the technical design against the original requirement, which is a very common cause of time overruns and cost. A prototype can be useful for this.

  • Use design patterns: Do not reinvent the wheel. Patterns save design time, reduce mistakes, and promote a solution that better conforms to best practice.

The technical design will include decisions on what technologies, frameworks, and patterns we will use. We may revert some decisions later on, but the majority we need to be sure we get right first time.

One such design element is the data structures. Once we start using them in code and the UI, it makes any changes to this more and more difficult. Some elements can't easily be reverted, such as whether to use table inheritance or not.

Table inheritance is a little like class inheritance. For example, we may have a core vehicle table, and specialized tables that inherit its properties (fields) and methods. As a more specific example, an articulated truck will have different attributes compared to a company car.

Data structure design considerations

The data structure architecture within Dynamics AX is breathtaking. When designing the technical structure, the tables and views should be considered along with classes as part of your static structure.

Note

We are not making the classes persist in the database. The table definition may be designed on object-oriented (OO) principles, but we are using this to define physical tables that are transacted on reliably.

The key concepts within this are described in the following sections.

Extended data types

In traditional database design, a field tended to be one of a limited set of primitive types, such as string, number, and so on. The extended data type (EDT) system in AX allows us to define types with extended properties.

With this, we can control the following categories of properties:

Appearance

For example, the label, help text, size (string), alignment, and other type-specific properties.

Behavior

Direction, for example, RTL and presence information.

Business intelligence

Information used by the system to generate the OLAP database.

Data

A reference table, internal ID information, or a reference form (the form used to open the record identified by the database relation).

Relationships

For the example of the ItemId EDT, this would specify that this EDT references InventTable.ItemId.

In this way, the system knows when the EDT is associated with a field on a child table and which table and record it references. Additionally, the table will often have a reference to the form that is used to edit the data, allowing the user to quickly navigate to the details form.

The specific properties aren't important for now, but understanding the concept is. Using EDTs ensures database consistency (primarily type and size) and user interface consistency (label, help text, and so on). This is done with very little effort, as we only have to change the EDT properties. Even more powerfully, changing the size of an EDT will change the size of all fields that reference it.

Therefore, we will always use an EDT when creating a field, and almost always use EDTs as variable declarations and method parameters. We can override most of the other properties on the table field, but we rarely do this.

Note

A key benefit is that we can control these properties with little effort, ensuring consistency throughout the user interface.

In some cases, we need to have a minor difference; for instance, we may wish to change a label when used in a specific context. Rather than changing the field label, it is better to create a new EDT that extends the primary EDT.

It is possible to change standard EDTs, but great care must be taken, as we need to know the full effects of the change. The choice between using standard EDTs (for example, for description fields) or creating new EDTs will be covered when we use them in the next chapter.

Base enums – enumerated types

Base enums are what is more commonly known as enumerated types. They provide a list of options that are stored as a number in the database; the user interface will always display the corresponding text. They are equivalent to integers, and can be cast between the integer and the symbol (text).

Enums are great for status fields, where we need to have code written against a specific value. Writing code against number or string literals is bad practice. Should the option not exist or be removed from the enum's definition, we will get a compilation error when the code is compiled.

An example enum is SalesStatus, which contains the following elements:

Symbol

Label (based on en-us)

Enum value

None

None

0

Backorder

Open order

1

Delivered

Delivered

2

Invoiced

Invoiced

3

Canceled

Canceled

4

You should always reference the symbol in the code. AX will understand that and translate it into the Enum value.

Tables

The table definitions stored within AX synchronize with the business database in SQL Server; often, this is automatic. No changes should be made to the SQL Server table definition, as this will be overwritten whenever the database is synchronized.

The table definition information controls both the user interface and how the physical table in SQL Server is created. This includes table properties, field definitions, and indexes. Relationships and referential integrity constraints are not created within SQL Server; these are managed within AX. They control what happens to a child table when a record is deleted or the primary key is renamed. The field definitions also control both the user interface and the physical field in SQL Server. These are usually set by the EDT it is associated with.

A key differentiator for tables is that we can create methods and override table event methods such as validateField, validateWrite, modifiedField, insert, delete, and so on. This allows us to place table-level validation and events on the table centrally and not on the interface.

In AX 2012, we can now have inheritance within tables and valid date/time states. Inheritance will allow us to have a base table, such as a vehicle table, and specialized tables that extend it, such as a bulk/loose product truck with silos and a vehicle designed to take pallets. The interface natively understands this relationship and can display records for all inherited tables in one grid control. This is covered in Chapter 2, Creating Data Structures.

The valid time state provides a way to version records. For example, as data about an employee changes, we can at any time ask the system what the data was at a specific point in time.

The key consideration here in the design is to determine the structure and events we need to handle, which in turn drives the required EDTs and base enums.

Views

Views are SQL view definitions, created by constructing a query of one or more tables. They can contain aggregates and also calculate view fields, which are essentially a piece of Transact-SQL that equates to a column in view.

These are useful when flattening data from normalized tables. The only real drawback is that they are read-only views, and when they are placed on the user interface in a grid control, the grid control becomes read-only. This means that if we add a column from a related table that is editable, it will become read-only in the grid control.

Maps

Maps provide a method of sharing code for similar tables. A good example of this is the pricing logic for sales and purchase order lines that is handled by the SalesPurchLine map.

Maps contain a list of reference fields, details of how these reference fields map to the actual table fields, and methods. This is best explained with an example, such as calculating the stocking unit quantity from the quantity ordered (for example, stored in cases and sold in each).

Rather than write this code on the sales order line and the purchase order line, we can do this once using a map. On the SalesPurchLine map, there are fields for PurchSalesUnit, ItemId, and SalesPurchQty. They are mapped as follows:

Map field

SalesLine field

PurchLine field

ItemId

ItemId

ItemId

PurchSalesUnit

SalesUnit

PurchUnit

SalesPurchQty

SalesQty

PurchQty

We can create a simplified method on the map that contains the following code snippet:

InventQty  calcQtyOrdered(Qty _qtySalesPurch = realMin())
{
    InventQty       qty;
    InventTable     inventTable;
    Qty             qtySalesPurch = _qtySalesPurch;

    if (qtySalesPurch == realMin())
        qtySalesPurch = this.SalesPurchQty;

    if (!qtySalesPurch)
        return 0;
    // this is actually calling a method that should exist 
    // on the actual table, for example, SalesLine
    inventTable = this.inventTable();


    qty = UnitConvert::qty(qtySalesPurch,
                           this.PurchSalesUnit,
                           inventTable.inventUnitId(),
                           this.ItemId);

    return decround(qty,InventTable::inventDecimals(this.ItemId));
}

On the sales and purchase order line table, we can call the preceding method. An example from the PurchLine table is as follows:

AmountCur calcLineAmount(Qty  qty = this.PurchQty)
{
    AmountCur ret;

    if (this.LineDeliveryType != LineDeliveryType::OrderLineWithMultipleDeliveries)
    {
        ret = this.SalesPurchLine::calcLineAmount(qty);
    }

    return ret;
}

The map will then automatically construct itself using the field mapping. Hence, we call methods on the map as if they are static methods with the :: sign. So, when called from the sales order line, this.PurchSalesUnit becomes SalesLine.SalesUnit and this.SalesPurchQty becomes SalesLine.SalesQty.

This can be a useful feature for reusing code across tables that provide similar functionalities.

Classes

Class definitions with AX provide functionality similar to C++, C#, or Java classes, in that they support inheritance and encapsulation. Interfaces can also be used and implemented in a way similar to C#.

Classes are created for the following purposes:

  • User interface interaction

  • Table event handling

  • Services

  • General processing (for example data updates, batch routines, and so on)

Although it is common to use a class to handle table events, the table itself will handle the interaction with the database. Form interaction classes are not mandatory for list pages, such as Accounts receivable | Common | Customers | All customers, but should be used on data entry forms that require logic. This ensures consistency and allows easier maintenance of logic.

When designing the static (mainly table and class) structure, we should break the design down so that we can easily expose that task as a service. An example can be a class that takes a vehicle out of service. This may perform many tasks: checking whether it was planned on loads, replacing the vehicle on the basis of a rule set, changing the status of the vehicle, and so on.

We may have other requirements to simply change the status of vehicle or associate suitable vehicles with unallocated loads. We have already written the code to change the status and the code to find a suitable vehicle. If we had classes for finding a suitable vehicle, changing status, and so on, we could've reused them, be it on a form or from code or linked to a service that could be used by a mobile application.

The point here is that we should break discrete pieces of functionality down into separate classes, as it then become much easier to reuse later on.

Forms

Most forms will be built from templates, which help us provide a consistent user interface that will look and feel much like the rest of AX. The helps reduce training time, reduce user error, and improve end user acceptance.

The following templates are available:

  • A list page

  • A details form—master

  • A details form—transaction

  • A simple list

  • A simple list, with a details section

  • A table of contents

  • A dialog

  • A drop dialog

The list page is our main entry point to both master data (items, customers, and so on) and transactional forms, such as sales orders.

The list page provides the user with a searchable list of records, with a button ribbon allowing the user to interact with the record, for example, Post sales invoice. They also provide key business intelligence about the current record, which means we don't have to navigate to the details form to make a decision on the record in question.

There are two types of details forms: master and transaction. Master forms are like customer and item forms, while sales order details and purchase order details are transaction forms. Details forms are designed to be opened from a list page.

Simple lists are useful for setup groups, where the form contains only a grid of a few fields. These are useful for simple lists of setup data. The simple list with details version contains a grid on the left and a details section that can be arranged into tabs to present many fields. Both of these form types are designed to be opened from the content area or menu.

Tables of contents are designed to be used for parameter forms. Although they may act on more than one data source (table), the tables will typically have a single record.

Dialog and drop dialog are similar in that both are designed to ask for limited information and then trigger an action. Both are usually called from another form. The difference is in how they are presented. The drop dialog will appear to drop down and be a part of the calling form, whereas a dialogs appears as a pop-up window. The difference is cosmetic, but drop dialogs are often preferred as they can't fall behind the current window.

 

Designing test plans


There are two main types of testing: unit testing and integration (process) testing. We are more concerned with unit testing.

Unit testing primarily ensures that the code performs functions for the functional design. We may also have performance requirements, where we need to test the code under a simulated load. AX provides a method to do this through a test project, where we can extend the test framework to write specific test cases.

These work well when simulating the load against the live hardware environment. We can use a range of performance tools to ascertain where performance bottlenecks may lie and correct them. It is better to know before "go live" that we have a bottleneck.

Even with this framework in place, manual testing is often the best method, especially since we are typically writing code based on database and UI interaction.

Let's take an example of a vehicle status change requirement. In this case, we will list the conditions that allow the status change to occur, and what should happen.

Status changed to

condition

Result

Available

Status: created

Vehicle: not acquired

Error "Vehicle not yet acquired"

Status remains unchanged

Available

Status: created

Vehicle: acquired

Success

Status changed to Available

Not available

Status: created

Vehicle: not acquired

Error "Vehicle not yet acquired"

Status remains unchanged

We then test our code to ensure that these statuses are being followed. Because we have one class that handles the status change, the form button, service call, and code call should also work. "Should" does not mean "will" of course, so each should be tested individually.

One of the biggest fears and causes of end user complaints is regression. The users involved in testing are usually key users or process owners, who are already busy with additional work brought on by an implementation. It is often their job to train their users, and "sell" the system's benefits; user buy-in is critical for successful user adoption.

There are two causes of regression: code that breaks other code or a change to a process that is incompatible with another process. The latter is mitigated by getting a solution architect or lead consultant who is responsible for the solution as a whole.

Code regression can be caused by the simplest change, and these changes are often the main cause of regression, as testing is often skipped in these cases. This is mitigated by thinking of testing as a component of the technical design, and having good technical documentation. The risks are further reduced if developer notes points where regression might occur, as the code is being written. Since the code that might be affected is commented with the TDD or FDD reference, it should be easy to locate the test plan to check for regression.

 

Summary


In this chapter, we covered the steps that we take to start up a new project. The actual steps for each new development may vary, depending on the scale of the work required. The key points to take away are that we should target the correct layer, use a specific model, place our work in a project, produce test cases for our solution, design the technical design, and use source control.

This preparatory work may seem a lot to do before starting work on a new development, but it pays off in dividends later. In the next chapter, we will design and create the data structures required for our solution.

About the Authors

  • Simon Buxton

    Simon Buxton has worked with Dynamics 365 for Operations since its earliest incarnations, starting out as a consultant and developer in early 1999 when Dynamics 365 for Operations was known as Damgaard Axapta 1.5. He quickly became a team leader at Columbus IT Partners and carried out one of the first Axapta implementations in the UK before joining a new reseller, Sense Enterprise Solutions, as its technical director. Sense Enterprise Solutions enjoyed a global reach through the AxPact alliance, where Simon was placed as AxPact's Technical Lead.

    Simon played a major role in growing the company into a successful Microsoft partner and was the Technical Lead on a number of highly challenging technical projects around the world, ranging from the UK, to Bahrain, to the USA. These projects include developing solutions for third-party logistics, multichannel retail, and eventually developing an animal feed vertical, as well as integrating Dynamics 365 for Operations into production control systems, government gateways, and e-commerce solutions, among others. Now, working with Binary Consultants, he was part of a team that implemented the first Dynamics 365 for Operations implementation with support from Microsoft as part of the Community Technical Preview program (CTP). The knowledge gained as part of this process led to the creation of this book.

    Simon has also worked on Mastering Microsoft Dynamics AX 2012 R3 Programming and Microsoft Dynamics AX 2012 R2 Administration Cookbook.

    Browse publications by this author
  • Mat Fergusson

    Mat Fergusson started his journey into software development in 1998 by studying software engineering at Sheffield University. After graduating, Mat took to working in IT infrastructure, quickly progressing from desktop support to infrastructure implementation and management.

    Armed with real-world experience of supporting users and seeing how applications and infrastructure are actually used, Mat began moving back into full-time application development, building classic ASP applications at the tail end of the .com boom.

    Mat was among the very early adopters of Microsoft's next generation development platform, .NET. Over the next few years, Mat would develop numerous web applications and integration projects using VB.NET and later C#, and in 2005, he started developing mobile business applications built on the Windows CE platform years before the iPhone made mobile applications ubiquitous.

    After completing the first release of an award-winning hosted health and safety mobile application, Mat decided to gain some broader experience and embarked on a one and a half year world tour, which saw him broadening both his IT and life skills by working for the Enterprise Applications division of HP in New Zealand and becoming a certified dive master in Thailand.

    Returning to the UK, Mat teamed up with his old colleagues and between them, they founded Binary Consultants, where he continues to work today. In the last 6 years, Mat has continued to refine his .NET development skills in his role as .NET Lead at Binary, and has been responsible for several highly specialist web applications for the cosmetic industry in Russia and the rapidly growing online gaming industry in Malta.

    In the last 2 years, Mat has started cross training in AX development, an experience that has helped him directly in writing this book with Simon. Mat's current specialty however, is the development of .NET applications for Binary's clients that extend the capabilities of AX by interfacing with the WCF services exposed by the AIF, introducing rich visualization and interactions that simply aren't possible with the AX client.

    Browse publications by this author

Latest Reviews

(2 reviews total)
Never received it
Concise, just what I need

Recommended For You

Book Title
Access this book and the full library for just $5/m.
Access now