Custom Aggregate Functions
Exago comes with a number of functions that can be used to make formulas in the Formula Editor. Administrators may create additional custom functions, using high level coding languages, which will be accessible to end-users of the Report Designer. In Exago v2019.2+ administrators may also create custom aggregate functions. Custom Aggregate Functions will be available in any formula editor in which the existing built-in aggregate functions are also available.
Custom Aggregate Functions can be written in C# or VB.NET and can take as many input arguments as needed. They can get and set elements of the current session state of Exago such as Parameter values. See the article on SessionInfo for more information.
Creating Custom Aggregate Functions
Custom Aggregate Functions may be created programmatically through the .NET API or manually through the Web Application. This section details how to create Custom Aggregate Functions through the Web Application but contains important details about programming the aggregate function which will apply to the .NET API as well.
- In the Admin Console, navigate to Extensions > Aggregate Functions then click the Add icon at the top of main menu. This will open a new Custom Aggregate Function tab.
Each Custom Aggregate Function has the following properties:
Note
The Description and Category properties below support multi-language functionality, where an Id from a language file instead of a static string may be supplied. For more information, see the article on Multi-Language Support.
Name
A name for the function that will be displayed to the end user and will be used to call the function. This name may only contain letters, numbers and underscores, and must be different from any of the built-in aggregate functions.
Description
A description of the function that will be displayed to the end user when building a formula in the Formula Editor.
Category
A way of categorizing/grouping similar functions together. Custom Aggregate Functions may be assigned to any existing category or to a new category. By default, custom aggregate functions are added to the Aggregate category unless a different one is chosen.
To create a new category:
- For all applicable language files, add a new language translation ID for the new category name. The element ID must begin with
FormulaEditor
and end withNode
. For example:<element id="FormulaEditorVeryCoolFunctionsNode">Very Cool Functions</element>
- Select Other from the Category dropdown list.
- An input field entitled Specific Category Name (Optional) appears. Enter the language file ID created in step 1.
Important
Providing a static text string that does not match a language file ID for the Specify Category Name (Optional) field is not valid.
Return Type
A return type must be specified for each Custom Aggregate Function. This field can be defined as a String, Integer, Decimal, or Date, and determines the expected return type of the function.
Prevent In-Database Grouping When Included in Detail Section
If the Custom Aggregate Function is called from a Detail section of a report and that Detail section is suppressed (hidden), setting this flag to True will prevent Exago from requesting the aggregation be done in the database. Instead aggregation will be done in memory insuring that the Custom Aggregate Function is called for each Detail row.
If False, Exago’s normal behavior determined by the Database Aggregation setting is utilized. If applicable, aggregation will be done in the database and then the Custom Aggregate Function will be called afterwards. This might cause trouble if the function is intended to work on unaggregated or ungrouped data.
For example, most functions that build or manipulate memory storage with GetStoredValue/SetStoredValue should have this flag set to True.
This flag will have no affect if the Custom Aggregate Function is called from any other section besides a Detail section.
Note
If Exago’s Database Aggregation setting is False, then aggregations will never be done in the database regardless of the setting of the Prevent In-Database Grouping When Included in Detail Section flag.
Arguments
Click Edit Argument Info to show a dialog for managing arguments.
Arguments are passed to the code as an array of generic objects, accessed as args[]
. Custom Aggregate Functions have two required arguments, dataToAggregate
and recordLevel
.
- dataToAggregate: the data field or formula to aggregate. Can be renamed, but must always be the first argument.
- recordLevel: indicates whether aggregation should occur at the record level or entity level. If true, aggregation occurs on the record level. Can be renamed, but must always be the last argument. Refer to the articles on Aggregate Functions and the Admin Console‘s Other Settings for more information on how this argument works.
Important
recordLevel
will evaluate to true if it is set to any true value (as returned by functions like True(), a nonzero number, or a non-empty string).
To add additional arguments to the function, click the Add Argument button.
To remove arguments from the function, click the Delete Row icon at the end of the respective row.
Arguments have the following properties:
Note
Both Name and Description properties below support multi-language, where an Id from a language file instead of a static string may be supplied. For more information, see the article on Multi-Language Support.
Name
The name of the argument, which will appear as a placeholder in the function parentheses and in the function’s description tooltip.
Description
A description for what the argument is used for which will appear as a tooltip when the placeholder name is selected.
Optional
Check the box if a value for the argument does not need to be supplied when the function is called. Leave the box unchecked if a value must be supplied.
If a user does not supply a required argument, the formula editor will highlight the error.
Optional arguments are surrounded by brackets [ ] in the function’s description tooltip.
Program Code
Language
The programming language of the code for the function. Either C# or VB.NET.
References
A semicolon-separated list of any libraries that need to be referenced by the Custom Aggregate Function. The DLLs must be present in the bin
folder of the Exago Web Application, as well as any Scheduler bin
folders, and the Web Service API, if applicable.
Note
System.dll
does not need to be listed as a reference as it is already available.
Namespaces
A semicolon-separated list of any namespaces that need to be referenced by the Custom Aggregate Function.
WebReports.Api.Custom; WebReports.Api.Common;
will be added automatically as they are required.
Code Editor
The code editor contains the program code for the Custom Aggregate Function. Unlike Custom Functions, the program code for Custom Aggregate Functions accommodates a full class definition.
A Custom Aggregate Function must contain at most one class that implements the ICustomAggregator
interface. The code may include more than one class definition, but no more than one class should implement ICustomAggregator
.
Depending on which language chosen, the code editor will pre-fill with a code stub as a general starting suggestion. This stub is an empty class which implements the ICustomAggregator
interface. Examples of both C# and VB stubs are shown below.
C# Code Stub
public class MyCustomAggregator : ICustomAggregator { public void AddValue(SessionInfo sessionInfo, object value, params object[] args) { } public object Result(SessionInfo sessionInfo) { } }
VB Code Stub
Public Class MyCustomAggregator Inherits ICustomAggregator Public Overrides Sub AddValue(ByVal sessionInfo As SessionInfo, ByVal value As Object, ParamArray args As Object()) End Sub Public Overrides Function Result(ByVal sessionInfo As SessionInfo) As Object End Function End Class
Note
To use a .NET Assembly for custom aggregate functions, first add it to the applicable bin folders. Then add the assembly as a reference in the Code Editor.
During report execution, the conditions under which Exago will call AddValue
change depending on what is passed to the Custom Aggregate Function’s dataToAggregate argument. This mirrors the behavior of the built-in aggregate functions:
- If a data field is passed, and the function’s recordLevel argument is false,
AddValue
is called when the key of the data field’s data object in the current record is different from that of the previous record. If recordLevel is true,AddValue
is called for every record. - If a parameter is passed,
AddValue
is called for every record. - If a formula or cell reference is passed,
AddValue
is called for every record.
Result
is called when the current break section has terminated. The aggregation result should be returned here. An explanation of when section processing ends is below in the following paragraphs.
When this Custom Aggregate Function is used on a report, Exago will instantiate a new instance of the class implementing ICustomAggregator
once at the beginning of report execution, and again every time the section that the Custom Aggregate Function appears in breaks. This means that ICustomAggregator
implementations will only aggregate within whichever section iteration is currently being processed, and aggregation starts over at the beginning of each new section.
A section breaks when its corresponding sorting entity’s unique key changes. For example, consider a report with Products organized into Category groups. To know when a new product Category starts and the previous Category ends (and thus when to display the appropriate section headers/footers and to perform aggregation), Exago looks for the unique key of the Category entity to switch to a new value, this is a section break.
If the custom aggregate function is in a:
- Detail section, a new
ICustomAggregator
is instantiated once before the first record is processed, then again before every other record is processed. - Group Header, a new
ICustomAggregator
is instantiated once before the first record is processed, then again after every other Group Header with the same group break is processed. - Report Footer, a new
ICustomAggregator
is instantiated only once, before the first record is processed.
Click the Test Execution icon to test the code for errors.
ICustomAggregator Interface
public interface ICustomAggregator { void AddValue(SessionInfo sessionInfo, object value, params object[] args); object Result(SessionInfo sessionInfo); }
The ICustomAggregator
interface defines two functions, AddValue
and Result
. There must be one and only one class defined in the Custom Aggregate Function‘s program code that implements both of these functions.
void AddValue(SessionInfo sessionInfo, object value, params object[] args)
value
: The value to aggregate. The cell data derived from thedataToAggregate
argument passed to the custom aggregate function is passed here.args
: subsequent arguments passed to the custom aggregate function are made available here.args[0]
here will be the argument followingdataToAggregate
in the custom aggregate function call.
object Result(SessionInfo sessionInfo);
Called when the current break group has terminated. The aggregation result should be returned.
To complete the creation of the Custom Aggregate Function:
- Click Apply or Okay. Exago will check the code for compilation errors and display a warning if any are found.
- If there are no warnings, the Custom Aggregate Function is now available for use.
Editing Custom Aggregate Functions
- In the Admin Console, navigate to Extensions > Aggregate Functions.
- Click on the name of the Aggregate Function to be edited, then click on the Edit icon at the top of the main menu.
- Review the section on creating Custom Aggregate Functions to understand all of the available fields.
Deleting Custom Aggregate Functions
- In the Admin Console, navigate to Extensions > Aggregate Functions.
- Click on the name of the Aggregate Function to be deleted, then click on the Delete icon at the top of the main menu.
Examples
Several examples of Custom Aggregate Functions can be found with the Custom Aggregate Functions tag in our Support Center.