Understanding Report Controller Classes in Dynamics AX 2012

By Bill Thompson | July 7, 2015

*Please note that the following assumes the reader understands the Dynamics AX 2012 concept of using a data contract class for report parameter and a data provider class for retrieving or preparing data for a Dynamics AX 2012 report. If the reader is unfamiliar with this concept, please examine the following document: AX 2012 Report Programming model.

Report controller classes in Microsoft Dynamics AX 2012 were designed using the Model View Controller (MVC) concept. This concept divides a given software application or process into three interconnected parts, so as to separate internal representations of information from the ways that information is presented to or accepted from the user. More information on this pattern can be found in this Wikipedia article on MVC.

The Microsoft implementation of this concept states that custom report controller classes inherit from the X++ based class named SRSReportRunController. This is the framework class for running reports using the MVC pattern. For more information on this class, please see the following on MSDN: http://msdn.microsoft.com/en-us/library/srsreportruncontroller.aspx

The report controller class contains methods that allow you to work with the data objects at different stages of the process. The prePromptModifyContract() method in the controller class is the designated location to place the code for modifying queries, before they are displayed in the dialog. So, any caller-based modification, locking of ranges based on the caller or the addition of other data sources, can be done within this method. The preRunModifyContract() method can be used to do this as well, but this method is invoked after the report dialog has been displayed. This means that the user never gets an option to modify or see the changes made to the query.

The next portion of this article is going to walk the code path of a standard report in Dynamics AX 2012 and show what the ‘bits and pieces’ do when the controller is called, to help see what really happens during the use of the controller class. The report that will be examined is the Inventory Value Report. In Dynamics AX 2012, the navigation is Inventory Management >> Reports >> Status >> Inventory value >> Inventory value.

Upon examination we find that the report uses a controller class named InventValueReportController. This class extends the SRSReportRunController class, inheriting the methods from the parent class or classes that are needed to implement the MVC pattern.

The main method is entry point for this class, and looks like the following (Dynamics AX 2012 R3 is being used for this example):

public static void main(Args _args)
{
    InventValueReportController controller = InventValueReportController::construct();
    InventValueReportContract inventValueReportContract = InventValueReportContract::construct();

    controller.parmReportName(inventValueReportContract.parmReportName());
    controller.parmDialogCaption("@SYS323601");
    controller.startOperation();
}

At first glance, this looks pretty simplistic. The X++ code simply defines a variable named controller that contains an instance of the controller class, the data contract class is also defined and instantiated, the controller class is told the name of the report to run, a caption is provided for the dialog box that prompts the user for information, and the startOperation() method is called to run everything. In actuality, when the code is traced, this gets quite complex.

startOperation() calls the SRSReportRunController class method (as it is not overwritten in the current controller class), and runs the following code:

public SysOperationStartResult startOperation()

{

    // get the report contract. This will initialize it as well.

this.parmReportContract();

// call hook to change the contract before prompt is called.

this.prePromptModifyContract();

// maintain a unique id for each report run execution instance.

reportRunId = newGuid();

return super();

}

The report contract object is initialized, and the prePromptModifyContract method is called. This method is used to modify the report data contract PRIOR to any dialog being displayed to the end user. A unique Id is created for this report session, and the super() call is done.

The super() method call actually calls back into a class called SysOperationsController. The method being run looks like this:

public SysOperationStartResult startOperation()

{

if (this.prompt())

this.run();

return startResult;

}

If the user clicks the OK button on the prompt, the run method is called. The run() method is the code that exists in the InventValueReportController class:

public void run()
{
    InventValueReportContract inventValueReportContract = this.parmReportContract().parmRdpContract() as InventValueReportContract;
    InventValueReportInit inventValueReportInit = InventValueReportInit::construct();

    inventValueReportContract.parmTransactionId(appl.curTransactionId(true));
    inventValueReportContract.parmQuery(this.parmReportContract().parmQueryContracts().lookup(this.getFirstQueryContractKey()));

    InventValueReportController::setReportLayoutParameters(inventValueReportContract);
    if (this.isInBatch())
    {
        InventValueReportContract.parmSRSPrintSettings(this.parmReportContract().parmPrintSettings().pack());
    }
    this.saveLast();

    inventValueReportInit.parmInBatch(this.isInBatch());
    inventValueReportInit.parmCurrentBatch(this.parmCurrentBatch());
    inventValueReportInit.parmInventValueReportContract(inventValueReportContract);
    inventValueReportInit.createTasks();
}

This method initializes a few other classes that are specific to this report, and starts the processing using the createTasks() method call of the initValueReportInit class (variable declared and instantiated at the beginning of this method).

The createTasks() method does a LOT of processing that is specific to this report. The only line I really want to point out is the following:

inventValueReportPrint.run();

This calls the run() method from another instantiated class called InventValueReportPrint. This method takes the objects that have been created, and uses this information to run the report:

public void run()

{

InventValueReportController controller = new InventValueReportController();

controller.parmReportName(inventValueReportContract.parmReportName());

controller.parmReportContract().parmReportCaption("@SYS323601");

controller.parmDialogCaption("@SYS323601");

if (conLen(inventValueReportContract.parmSRSPrintSettings()) > 0)

{

controller.parmReportContract().parmRdpContract(inventValueReportContract);

controller.parmReportContract().parmPrintSettings(new SRSPrintDestinationSettings(inventValueReportContract.parmSRSPrintSettings()));

}

// Do not show the dialog in the report viewer

controller.parmShowDialog(false);

controller.runReport();

}

The last line actually starts the generation of the report using the prior information, the data contract class, and the data provider class to retrieve the information.

In summary, this article was intended to try to explain in a bit more detail what a Dynamics AX 2012 Report controller class really does, and give a small insight into some of the core objects that are used when a report is run.

 

Related Posts

Recommended Reading:

6.29.22 Dynamics CRM

Reduce Manual Data & Increase Productivity with Dynamics 365 for Sales

Dynamics 365 for Sales has a ton of great features to help automate processes for you and your team to […]

Read the Article

Dynamics 365 Business Central Boolean Field Bug Temporary Fix

If you are a Dynamics 365 Business Central cloud (SaaS) customer who is using Edge or Chrome to run the […]

Read the Article

Using Non-Sequential Numbering to Prevent Locking In Your Dynamics 365 Business Central System

Running into locks in your system? Enable non-sequential numbering on your number series to prevent number series locking issues! As […]

Read the Article
6.24.22 Dynamics GP

Uncommonly Used Features: Setting Up Account Categories in Dynamics GP

This is the final part of my current series on Uncommonly Used Features in Dynamics GP. In this post, I […]

Read the Article

Increase User Productivity in Dynamics 365 Business Central with These 10 Tips

There are constantly evolving ways for you to increase user productivity in Dynamics 365 Business Central. Here are 10 tips […]

Read the Article

Star Tribune Lists Stoneridge as a Top 200 Workplace for 2022

Stoneridge Software’s emphasis on creating a positive and flexible culture has earned recognition as a top workplace in Minnesota. The […]

Read the Article
6.14.22 Dynamics GP

Uncommonly Used Features – Reconciling Sub-ledger to GL using the Reconcile Routines in Dynamics GP

As we continue the uncommonly used features series, with this post I want to show you how to reconcile your […]

Read the Article

Organize and Prioritize Your Resources with Dynamics 365 Field Service

As a manager, Dynamics 365 Field Service lets you optimize the use of your employees, their skillsets, and other resources […]

Read the Article

Stoneridge Software Cracks the Top 20 on Bob Scott’s Top 100 VARs 2022

Stoneridge Software is ranked at #20 on Bob Scott’s Top 100 VARs for 2022. Each year, industry publisher, Bob Scott, […]

Read the Article

Start the Conversation

It’s our mission to help clients win. We’d love to talk to you about the right business solutions to help you achieve your goals.

Subscribe To Our Blog

Sign up to get periodic updates on the latest posts.

Thank you for subscribing!

X