D365 F&O • X++ INTERVIEW
SSRS Reports in Dynamics 365 Finance & Operations
Question 34 — The RDP development pattern and how to customize standard reports.
Interview Question
How do you develop an SSRS report in Dynamics 365 Finance & Operations? Explain the
Report Data Provider (RDP) pattern and its components, and describe how to
customize a standard report that is not extensible.
Model Answer (Short)
A new SSRS report is typically built using the Report Data Provider (RDP) methodology. The RDP
pattern has four main parts: a temporary table that holds the report data, a
data contract class that defines the parameters, the RDP class (extending
SRSReportDataProviderBase) that runs the business logic and fills the temp table, and a
controller class that orchestrates execution and the dialog. Because report objects are
not extensible, you customize a standard report by duplicating the report object,
while the related controller, DP classes and temp tables should be handled by
extension of the standard where possible.
The RDP Pattern Components
Four building blocks
- Temporary table — a temp table (often
TableType = TempDB) that stores the rows the report renders. - Data contract — a
[DataContractAttribute]class defining the report parameters. - RDP class — extends
SRSReportDataProviderBase; itsprocessReport()builds and inserts the data into the temp table. - Controller — extends
SrsReportRunController; manages parameters, the dialog and execution, and is the entry point from a menu item.
RDP FLOW
Contract (params) → RDP class (logic) → Temp table (data) → Report design
Customizing a standard report
- Report objects are not extensible, so a standard report is customized by duplicating the report object.
- The related controller, DP classes and temp tables should be developed by extension of the standard where possible.
- Duplicate only what must change; reuse standard logic through extensions to stay upgrade-friendly.
Prerequisites (Rule 5)
- Visual Studio with the Dynamics 365 developer tools and SSRS extensions.
- A custom model / package for your objects.
- A temporary table for the report data and an output menu item to launch the controller.
Code Example — Data contract
[DataContractAttribute]
class AbcSalesReportContract
{
CustAccount custAccount;
[DataMemberAttribute('CustAccount')]
public CustAccount parmCustAccount(CustAccount _custAccount = custAccount)
{
custAccount = _custAccount;
return custAccount;
}
}
RDP class (fills the temp table)
[SRSReportParameterAttribute(classStr(AbcSalesReportContract))]
class AbcSalesReportDP extends SRSReportDataProviderBase
{
AbcSalesReportTmp tmp; // temp table (report data source)
[SRSReportDataSetAttribute(tableStr(AbcSalesReportTmp))]
public AbcSalesReportTmp getTmp()
{
select * from tmp;
return tmp;
}
public void processReport()
{
AbcSalesReportContract contract = this.parmDataContract();
CustAccount cust = contract.parmCustAccount();
SalesTable salesTable;
while select salesTable
where salesTable.CustAccount == cust
{
tmp.clear();
tmp.SalesId = salesTable.SalesId;
tmp.CustAccount = salesTable.CustAccount;
tmp.insert();
}
}
}
Controller (entry point)
class AbcSalesReportController extends SrsReportRunController
{
public static void main(Args _args)
{
AbcSalesReportController