Search This Blog

Monday, July 6, 2015

How to easily register many predefined reports using the ReportsV2 module

I wanted to repost a solution for a scenario logged by our old customer Mario Blataric in the past:

"...Also, there is one more thing - report registration. Currently, every V2 report needs to be registered in Module.cs. That's also fine for 10-20 reports, but when you have 1000 lines of code for just registering reports ... not fun.
Give Report properties like Caption, IsInPlace, AutoRegister and other required properties and just do registration automagically if AutoRegister = true (if for some reason someone wants to add report which doesn't want to be accessible through Reports class). "

Here is a possible solution description from the corresponding Support Center ticket:

While in XAF we cannot add new properties like Caption, Category, IsInplace, ParametersObjectType to the base XtraReport class from our shared DevExpress XtraReports library (essentially because these properties will have meaning only in XAF solutions and will not make much sense in non-XAF applications), 
it is possible to implement a custom .NET code attribute with all the required options:
public class RegisterReportAttribute : Attribute { public string DisplayName { get; private set; } public Type DataType { get; private set; } public Type ParametersObjectType { get; private set; } public bool InplaceReport { get; private set; } public RegisterReportAttribute(string displayName, Type dataType = null, Type parametersObjectType = null, bool isInplaceReport = false) { DisplayName = displayName; DataType = dataType; ParametersObjectType = parametersObjectType; InplaceReport = isInplaceReport; } }
Once you did so, you can use this custom attribute with your XtraReport descendants as follows:
[RegisterReport("Report1")] public partial class ContactsReport : XtraReport

Register all reports marked with this attribute via a helper class:
public static class RegisterPredefienedReportsHelper { public static IEnumerable<PredefinedReportDataContainer> FindReports() { List<PredefinedReportDataContainer> reportContainers = new List<PredefinedReportDataContainer>(); foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { if (typeof(XtraReport).IsAssignableFrom(type)) { var attributes = type.GetCustomAttributes(typeof(RegisterReportAttribute), false); if (attributes.Length > 0) { RegisterReportAttribute reportInfo = ((RegisterReportAttribute)attributes[0]); reportContainers.Add(new PredefinedReportDataContainer(type, reportInfo.DisplayName, reportInfo.DataType, reportInfo.ParametersObjectType, reportInfo.InplaceReport)); } } } return reportContainers; } }

This helper class is still supposed to be used with the standard PredefinedReportsUpdater class in the body of your ModuleBase descendant (typically located in the Module.cs file) as follows:
namespace YourSolutionName.Module {   public sealed partial class YourSolutionNameModule : ModuleBase public override IEnumerable<ModuleUpdater> GetModuleUpdaters(IObjectSpace objectSpace, Version versionFromDB) { ModuleUpdater updater = new DatabaseUpdate.Updater(objectSpace, versionFromDB); PredefinedReportsUpdater predefinedReportsUpdater = new PredefinedReportsUpdater( Application, objectSpace, versionFromDB); foreach (var container in RegisterPredefienedReportsHelper.FindReports()) { predefinedReportsUpdater.AddPredefinedReport(container); } return new ModuleUpdater[] { updater, predefinedReportsUpdater }; } } }

Refer to the 5th step of the eXpressApp Framework > Concepts > Extra Modules > Reports V2 Module > Create Predefined Static Reports tutorial for more information on this standard registration procedure.


  1. Hi Dennis, is there a way to refresh the list of in-place reports after you have added a new one. Usually you need to logout and login again for the reports to show

  2. I found how to refresh the reports :) my bad I did not look that deep into the documentation