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.
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.
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.
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.
A description of the function that will be displayed to the end user when building a formula in the Formula Editor.
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:
FormulaEditor
and end with Node
. For example:
<element id="FormulaEditorVeryCoolFunctionsNode">Very Cool Functions</element>
The language filed ID is provided in the Specify Category Name (Optional) field
Formula Editor dialog showing the custom category name Very Cool Functions
Important
Providing a static text string that does not match a language file ID for the Specify Category Name (Optional) field is not valid.
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.
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.
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
.
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
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.
The name of the argument, which will appear as a placeholder in the function parentheses and in the function’s description tooltip.
A description for what the argument is used for which will appear as a tooltip when the placeholder name is selected.
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.
The programming language of the code for the function. Either C# or VB.NET.
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.
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.
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.
public class MyCustomAggregator : ICustomAggregator { public void AddValue(SessionInfo sessionInfo, object value, params object[] args) { } public object Result(SessionInfo sessionInfo) { } }
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:
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.AddValue
is called for every record.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:
ICustomAggregator
is instantiated once before the first record is processed, then again before every other record is processed.ICustomAggregator
is instantiated once before the first record is processed, then again after every other Group Header with the same group break is processed.ICustomAggregator
is instantiated only once, before the first record is processed.Click the Test Execution icon to test the code for errors.
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 the dataToAggregate
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 following dataToAggregate
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:
Several examples of Custom Aggregate Functions can be found with the Custom Aggregate Functions tag in our Support Center.