AX2012 SSRS Reporting Data Provider class decorations

Thursday, 22 October 2015

When you need to make an advanced report, or a document in AX2012, the you ought to be looking at a data provider based SSRS report. These are the situations that in previous versions would have meant a customer fetch method would be needed on the report. The combination of classes that go in to making one of these reports allow you to develop bespoke business logic with custom parameters.

In order to make those classes work, there are some decorations that you need to include, so the application knows what your classes and methods are, and how to deal with and display them.

There are only 2 classes that you really need in order to make a data provider based report. The data contract, and the data provider. Strictly speaking, you could get away with only the data provider, but the contract is the most interesting of the classes in terms of decoration options!

The Data Contract Class

The data contract is the class that defines the parameters that are going to be available on the report for the data sets in a given data provider. The UI builder class (that you can override if you want) can have a guess at how the parameters dialogue is going to be laid out, but there are a few different decorations that you can use within a data contract to give the UI builder some hints how it ought to be.

We’re aiming to produce the following dialogue:

Dialog

As you can see, there are 4 parameters in the dialogue, which are all produced using the data contract. These parameters are split into 2 groups, and laid out in a custom order (nothing ground breaking here!)

Here’s the class:

[
    DataContractAttribute,
    SysOperationGroupAttribute("Dates","Date Range","10"),
    SysOperationGroupAttribute("Other","Other Options", "11")
]
public class FdyGoodsInwardAdviceContract implements SysOperationValidatable
{
    FromDate    fromDate;
    ToDate      toDate;
    VendAccount vendAccount;
    DlvModeId   dlvModeId;

    [
        DataMemberAttribute,
        SysOperationGroupMemberAttribute("Dates"),
        SysOperationDisplayOrderAttribute("01")
    ]
    public FromDate parmFromDate(FromDate _fromDate = fromDate)
    {
        fromDate = _fromDate;
        return fromDate;
    }

    [
        DataMemberAttribute,
        SysOperationGroupMemberAttribute("Dates"),
        SysOperationDisplayOrderAttribute("02")
    ]
    public ToDate parmToDate(ToDate _toDate = toDate)
    {
        toDate = _toDate;
        return toDate;
    }

    [
        DataMemberAttribute,
        SysOperationGroupMemberAttribute("Other"),
        SysOperationDisplayOrderAttribute("01")
    ]
    public VendAccount parmVendAccount(VendAccount _vendAccount = vendAccount)
    {
        vendAccount = _vendAccount;
        return vendAccount;
    }

    [
        DataMemberAttribute,
        SysOperationGroupMemberAttribute("Other"),
        SysOperationDisplayOrderAttribute("02")
    ]
    public DlvModeId parmDlvModeId(DlvModeId _dlvModeId = dlvModeId)
    {
        dlvModeId = _dlvModeId;
        return dlvModeId;
    }

    public boolean validate()
    {
        ...
    }
}

The first thing to note is that the class needs to be decorated with DataContractAttribute - this tells Dynamics AX that it is a Data Contract. That’s the only one that is required on the class - but also note that the class has to be public.

After that decoration, you can see that we have two SysOperationGroupAttribute decorations. These are completely optional, but they allow you to group your parameters together. The constructor for this class is as follows:

public void new(IdentifierName _groupName, LabelType _label, str _displayOrderKey, [FormArrangeMethod _arrangeMethod])

So the three required parameters are an Identifier (you’ll need this in a moment), a label (you ought to use a proper AX label), and display order - as a string rather than a number! The label will be used to give the group their title, and the display order will determine which order they appear in. As its a string, I personally like to make it a 2 digit identifier, just in case we get more than 10... I’ve got 2 groups here to hold my 4 parameters - you can have as many as you want; and not all parameters have to belong to a group, they can just go into the display order on the same level as a group - although if you are using groups, then I’d put all your parameters into one of them (its personal preference).

Next comes each of my accessor methods. They need to be decorated with DataMemberAttribute. Sadly this isn’t added with the parm code macro, so you’ll need to add it yourself.

I’ve also added a group membership (remember those from the class declaration), and a display order within the group. The group membership is done with SysOperationGroupMemberAttribute which takes the identifier of the group - which we defined in the SysOperationGroupAttribute in the class declaration. The display order is done with SysOperationDisplayOrderAttribute which is the same as the parameter of SysOperationGroupAttribute - it takes a string by which to sort the parameters; this gets evaluated after group membership, so you don’t have to be globally sorted, just within the group.

The final thing for the contract, is that it implements SysOperationValidatable - this means that it needs to have a public boolean method called validate - I’ve skipped the contents of the method here, but this is very useful for making sure that all necessary parameters are filled in before SSRS can complain - and you can give more sensible error messages than will be produced if you leave it to SSRS.

There are 2 other decorations that you can use on the data members: SysOperationLabelAttribute and SysOperationHelpTextAttribute but these are not necessary if you are using a suitable Extended Data Type (which you should).

The Data Provider Class

These are pretty easy decorations to understand. They’re not optional (if you want your code to be available to SSRS), and they follow a nice and simple format. Here’s the class structure:

[SRSReportParameterAttribute(classStr(FdyGoodsInwardAdviceContract))]
class FdyGoodsInwardAdviceDP extends SRSReportDataProviderBase
{
    FdyGoodsInwardAdviceTmp tempTable;

    public void processReport()
    {
        ...
    }

    [SRSReportDataSetAttribute("GoodsInwardAdvice")]
    public FdyGoodsInwardAdviceTmp getReportData()
    {
        select * from tempTable;
        return tempTable;
    }
}

There are 2 decorations you need in your class. The first is on the class decoration:

[SRSReportParameterAttribute(...)]

This decoration tells SSRS which class is the data contract, and therefore what parameters are going to be on the report to display the UI parameters. You should use the classStr method to pass in the name of your contract class to this decoration.

The second tells SSRS which methods contain your datasets.

[SRSReportDataSetAttribute(...)]

It takes a parameter of “Report Dataset Name” - its important to note that this cannot contain spaces. In this example, I have only a single dataset from the class, but the concept is the same for multiple datasets within a class, make sure to give them different report dataset names. e.g. "GoodsInwardAdviceHeader" and "GoodsInwardAdviceLine"