NoteThis version of the .NET API documentation is deprecated. A new version can be found at https://www.exagoaccess.com/api-docs/.
This article contains a list of examples for using the .NET API's various features. The .NET API can be used for many purposes, and the most common is to create secured access points for end-users via browser sessions. However, you can also use the API to create and manage schedules, generate config files and reports programmatically, edit existing reports, and more.
NoteThis guide is kept up to date for the most current version available. For a list of changes in the API, see the Updating Guide.
Getting Started
Exago BI .NET applications must include a reference to the files WebReportsApi.dll
and ExagoPuppeteerRasterizer.dll
, found in the bin
folder of the application installation directory. This contains all the classes and method groups necessary for the examples in this article.
Optional: If you are connecting to a .NET Assembly Data Source, you will need to include a reference to WebReportsAsmi.dll
. A reference to WebReports.dll
is unnecessary, except in some rare cases that are not discussed in this guide.
The following Exago BI namespaces are used in the examples in this guide:
- WebReports.Api
- WebReports.Api.Reports
- WebReports.Api.Common
- WebReports.Api.Data
- WebReports.Api.Roles
- WebReports.Api.Programmability
- WebReports.Api.Scheduler
- WebReports.Api.ReportMgmt
- WebReports.Api.Theme
As well as the following system namespaces:
- System.Collections.Generic
- System.Linq
- System.Xml
Contents
- API Object
- Sorts and Filters
- Settings
- Role Permissions
- Advanced Configuration
- Scheduling
- Managing Files and Folders
API Object
An API object must be instantiated at the start of an API application since it is the access point for all API activity. API objects also encompass sessions which are used to encapsulate user-specific changes, such as security and permissions settings.
NoteVariable names, such as "api" and "report", are declared in their respective sections in this guide, then referenced throughout the remainder.
Constructors
Basic constructor: appPath is the file path or virtual path to Exago base install.
Api api = new Api("appPath");
Specify a config file (other than the default WebReports.xml)
Api api = new Api("appPath", "configFn");
Custom config file and its location in Azure storage (must match web.config)
Api api = new Api("appPath", "configFn", "azurePath");
Let the host application configure log4net
Api api = new Api("appPath", bool isLogCustomConfig, "configFn");
Write to the default log file ([Temp]\WebReportsApiLog.txt
)
Logger logger = Log.GetLogger(); logger.Info("message"); // Writes at info level
API Action
The location to direct the Exago interface when first loaded. Edit or Execute actions work on an "active" report.
api.Action = wrApiAction.Home;
Hide tabbed UI
api.ShowTabs = false;
Active Report
Load a report from repository. Makes it the active report. "reportName" is the fully qualified path relative to the base report directory without the file extension. ReportObject is a generic class encompassing all report types.
ReportObject reportObject = api.ReportObjectFactory.LoadFromRepository("reportName");
Report is validated (checked for errors) unless overridden
ReportObject reportObject = api.ReportObjectFactory.LoadFromRepository("reportName", bool validate);
Manually validate
reportObject.Validate();
Check the errors list. See list of error types.
foreach (ReportValidationError error in report.ValidationErrors) { string.Format("Error: {0}\n\t{1}\n\t{2}\n", error.ReportErrorType.ToString(), error.Data1, error.Data2); }
Get the report type
string reportType = reportObject.ReportType.ToString();
Cast the report object to higher level class
Report report = (Report)reportObject;
Validate the export type
bool IsReportAllowPdfExport = report.IsExportTypeAllowed(wrExportType.Pdf); bool IsConfigAllowPdfExport = api.General.AllowPdfOutput;
Set the export type
report.ExportType = wrExportType.Pdf;
Launch Exago and Execute Report
To launch in a browser frame with specified Action, get the App URL to redirect the browser. Redirecting to the App URL closes the API to further changes. It should be the last thing done.
Get the App URL, with the default home page "ExagoHome.aspx"
string appUrl = api.GetUrlParamString();
Specify a custom Exago home page, "homePage" is the file name without the file extension
string appUrl = api.GetUrlParamString("homePage");
Set ShowErrorDetail to true, for more detailed user error messages
string appUrl = api.GetUrlParamString(null, true); // This is equivalent to: string appUrl = api.GetUrlParamString() + "?ShowErrorDetail=true";
Redirect the browser to the App URL (this will close the API to any further changes)
Frame.Src = baseUrl + appUrl;
GetExecute() Methods
As an alternative to API Action, some reports can be executed and the data returned directly to the host application. Since this does not launch Exago, this will not close the API, but report interactivity is not supported. Only bare HTML, JSON, and so on are returned. Acts on the specified report, not the active report.
Review the Executing Reports with the API article for full details and supported report types.
string reportHtml = report.GetExecuteHtml(); string reportJson = report.GetExecuteJson(); byte[] reportData = report.GetExecuteData(); string[] reportSql = report.GetExecuteSql();
Calling the GetExecute() methods triggers the following Server Events, if applicable:
Sorts and Filters
You can add sorts and filters to reports at runtime. After making changes, save back to the API for execution in the session.
api.ReportObjectFactory.SaveToApi(report);
Changes could be saved back to the report file on disk
api.ReportObjectFactory.SaveToRepository(report);
Save edited report as a new report
api.ReportObjectFactory.Copy(report, "newName", null);
Sorts
See the existing sorts in a report
foreach (Sort sort in report.Sorts) { string.Format("{0}, {1}\n", sort.SortText, sort.Direction); }
Add a new sort to a report
report.Sorts.Add(new Sort(api.PageInfo) { // Use object Alias name, as well as the field Alias name if set SortText = objectName + '.' + fieldName, Direction = wrSortDirection.Ascending });
Formula sort
SortText = string.Format("=Formula({{{0}.{1}}})", objectName, fieldName);
Sorts is an ordered list. Reorder the list to change the precedence of the sorts.
// Move a sort from position 3 to position 1 for (int i = 3; i > 1; i--) { Sort temp = report.Sorts[i - 1]; report.Sorts[i - 1] = report.Sorts[i]; report.Sorts[i] = temp; }
Filters
See the existing filters in a report
string filterString = ""; // Build a filter summary string for display foreach (Filter f in report.Filters) { filterString += string.Format("{0}{1} {2} {3}{4}", new string('(', f.GroupStartCnt), f.FilterText, f.DisplayOperatorText, f.DisplayValue, f.GroupEndCnt > 0 ? new string(')', f.GroupEndCnt) : ' ' + f.AndOrValue + ' '); }
Add a new filter
// Get the data field info (should first check that the report contains the entity) EntityColumn field = report.Entities.GetEntity("objectName").GetColumn("fieldName"); report.Filters.Add(new Filter(api.PageInfo) {
FilterText = field.FullName, // Object and field Alias names DataType = field.DataType, Operator = wrFilterOperator.OneOf, // This filter type takes multiple values DataValues = new DataValueCollection() { new DataValue(api.PageInfo, field) { Value = "value1" }, new DataValue(api.PageInfo, field) { Value = "value2" } } });
Group Min/Max filters
string groupFilterString = ""; // Build a filter summary string for display int i = 0; foreach (GroupFilter filter in report.GroupFilters) { groupFilterString += string.Format("{0} {1} for each {2} {3}{4}", filter.DisplayOperatorText, filter.FilterText, filter.GroupName, filter.IgnoreOtherGroups ? "ignoring other groupings" : "", (i < report.GroupFilters.Count()) ? ", " : "" ); i++; }
Add a new group filter
// Should check that the entity and sorts exist on the report EntityColumn field = report.Entities.GetEntity("objectName").GetColumn("fieldName"); Sort sort = report.Sorts.GetSort("sortName"); report.GroupFilters.Add(new GroupFilter(api.PageInfo) {
FilterText = field.FullName, // Object and field Alias names Operator = wrGroupFilterOperator.Maximum, GroupName = sort.SortText // Or sort.Entities[0].Name, or "EntireDataSet" });
See Top N filter
// Build a filter summary string for display // Reports limited to one Top N filter, max one foreach group per filter string topNFilterString = ""; if (report.TopNItems.Count() > 0) { if (report.TopNItems[0].UseTopNItem) { TopNItem filter = report.TopNItems[0]; topNFilterString = string.Format("{0} {1} {2}{3}", filter.Action == TopNAction.top ? "Top" : "Bottom", filter.Number, report.Cells.GetCellById(filter.CellId).DisplayText, (filter.ForEachGroup.Count() > 0) ? " for each " + filter.ForEachGroup[0] : ""); } }
Add Top N filter
// Check that the cell exists int cellId = report.Cells.GetCell(int row, int col).Id; TopNItem topN = new TopNItem(api.PageInfo) { Action = TopNAction.top, Number = int N, // the N in "Top N" CellId = cellId, ForEachGroup = new List<string> { }, UseTopNItem = true }; // Must be at zero-index position if (report.TopNItems.Count() == 0) report.TopNItems.Add(topN); else report.TopNItems[0] = topN;
Settings
Change the values of config settings and parameters dynamically, which often depend on user access rights. A dynamic config can be thought of as an extension of a Role, although Roles aren't necessarily required.
Configuration Settings
api.General.anySetting = newValue;
See Config File and API Setting Reference for the full list of config settings.
Storage Management Settings
Set Identity Keys
Set the value of one of the Storage Management identity keys. Specify the key (e.g. userid, classid) and the value as strings. In Exago's Storage Management implementation, the keys are
- userId
- classId
- companyId
- ownerId
Api.SetupData.StorageMgmtConfig.SetIdentity(string key, string value)
Set Default Access Flags
Set the value of the configuration's default access flags setting.
api.SetupData.StorageMgmtConfig.DefaultAccessFlags = ContentMetadata.ContentPermission.FullAccess;or
api.SetupData.StorageMgmtConfig.DefaultAccessFlags = ContentMetadata.ContentPermission.ReadOnly;
Set General Storage Management Properties
The names of the available properties can be found in the Storage Management section of the Config File XML Reference article. Refer to the specific sections of this article for setting Storage Management identity keys or options. In general, the properties are accessed via SetupData.StorageMgmtConfig
. For example:
//Enable report list and report XML caching api.SetupData.StorageMgmtConfig.ReportXmlCacheEnabled = true; api.SetupData.StorageMgmtConfig.ReportListCacheEnabled = true; //Set the timeout for both caches to 30 seconds api.SetupData.StorageMgmtConfig.ReportXmlCacheTimeout = 30; api.SetupData.StorageMgmtConfig.ReportListCacheTimeout = 30;
Utilize the Storage Management Options Collection
There is a dictionary of options passed around the Storage Management system that stores pertinent information for the database, but additional key-value pairs can be added.
Configure the Database Connection
api.SetupData.StorageMgmtConfig.SetOption("DbType", "SQLite"); api.SetupData.StorageMgmtConfig.SetOption("DbProvider", "Sqlite"); api.SetupData.StorageMgmtConfig.SetOption("ConnectionString", "Data Source=C:\\Program Files\\ExagoWeb\\Config\\Storage.sqlite");
Set a Custom Option
//add a custom option named user_Profile and set support_Administrator as its value api.SetupData.StorageMgmtConfig.SetOption("user_Profile", "support_Administrator");
Reading Options Data
Use StorageMgmtConfig.Option("key_name");
to read the values from the configuration.
Example 1:
textBox1.Text = api.SetupData.StorageMgmtConfig.Option("ConnectionString");
will fill textbox1
with the connection string to the Storage Management database.
Example 2:
api.SetupData.StorageMgmtConfig.Option("user_Profile");
will return support_Administrator
Parameters
Parameters are variables that persist throughout a session, and are reachable by extensions. They can be used to set custom environment variables. userId and companyId are two such built-in parameters for storing user information.
CautionThe .NET namespace
System.Web.UI.WebControls
also contains a class called Parameter. You may wish to alias one or both classes to resolve name conflicts.
using wrParameter = WebReports.Api.Common.Parameter;
List config parameters
foreach (Parameter parameter in api.Parameters) { string.Format("Name: {0}, Value: {1}\n", parameter.Id, parameter.Value); }
Get a specific parameter by Id
Parameter parameter = api.Parameters.GetParameter("parameterId");
Add a new parameter
api.Parameters.Add(new Parameter(api.PageInfo) { Id = "foo", // No spaces DataType = (int)DataType.String, Value = "bar" });
Non-hidden parameters are usable on reports
parameter.IsHidden = false;
Prompting parameters will ask the user for a value when running a containing report
parameter.PromptText = "Enter a value";
Prompting parameters can display a selection list based on a data field or custom SQL
Entity entity = api.Entities.GetEntity("entityName"); parameter.DropdownDataSourceId = entity.DataSourceId; parameter.DropdownObjectType = entity.ObjectType; parameter.DropdownDbName = entity.DbName; parameter.DropdownValueField = entity.GetColumn("colName").Name; parameter.DropdownDisplayValueField = entity.GetColumn("colName").Name;
Save to Disk
public void SaveConfigToFile(string fileName, bool forceAllValues)
The configuration data will be written to the current configuration file, or to the file name provided in the fileName
argument. Pass null to overwrite the current configuration file.
If forceAllValues
is true, all of the General settings will be written to the file. Otherwise, only those settings which are different from the defaults are written to the file. Default value is false.
For versions pre-v2019.2:
api.SaveData(bool isPermanent)
Creates .xml and encrypted .enc files in the Temp directory. If isPermanent = true, creates the files in the /Config directory, overwriting the existing config files.
Role Permissions
Roles are a neat way to encapsulate a collection of permissions. Roles also allow for some more fine grained control over data and folder access than the base config settings. Only one role can be active at a time.
Get a specific role
Role role = api.Roles.GetRole("roleId");
Create new role
api.Roles.Add(new Role(api.PageInfo) { Id = "roleId", IsActive = true });
Edit role settings
role.General.AnySetting = "value";
Folder/Object/Row Security
role.Security.Folders.IncludeAll = true; role.Security.Folders.Add(new Folder() { Name = "folderPath", ReadOnly = true }); role.Security.DataObjects.Add(new DataObject() { Name = "objectName" }); role.Security.DataObjectRows.Add(new DataObjectRow() { ObjectName = "objectName", FilterString = "filterString" });
Activate a role
role.Activate();
Advanced Configuration
You can dynamically change data sources, objects, joins, etc., in the API, or simply use these settings to programmatically generate a config file.
Data Sources
View data source
api.DataSources.GetDataSource("dataSourceName").DataConnStr;
Create a new data source
api.DataSources.Add(new DataSource(api.PageInfo) { Name = "dataSourceName", DbType = Constants.DatabaseType.SqlServer, DataConnStr = "connectionString" });
Data Objects
View data objects
foreach (Entity entity in api.Entities) { // three ways to identify an entity string.Format("Alias: {0}, Id: {1}, Database Name: {2}\n", entity.Name, // Alias entity.Id, // Id entity.DbName // Database Name ); }
Get a specific data object
NoteThis is the recommended way to get an entity by name, but there are other methods provided as well.
Entity entity = api.Entities.GetEntity("entityAlias");
// Returns null if it does not exist // Best to retrieve entities by Alias name, because Aliases are unique and required // Ids are unique, but not required; Db names are required, but not unique (across sources)
View object fields
foreach (EntityColumn column in entity.Columns) { string.Format("Alias: {0}, Database name: {1}\n", column.Name, // Alias (or actual if no alias) column.ActualName // Database name ); }
Create new data object
TipSet the
Id
property before theDbName
.
Entity entity = api.Entities.NewEntity(entityName); entity.DataSourceId = api.DataSources.GetDataSource("dataSourceName").Id; entity.ObjectType = DataObjectType.Table; entity.Id = "idName"; // Unique entity.DbName = "databaseName"; // Required entity.Name = "aliasName"; // Required, unique // Add key column entity.KeyColumns.Add(new KeyColumn(entity.GetColumn("colName").ActualFullName));
SQL Object
entity.SqlStmt = "SELECT * FROM Employees";
Add tenanting to object
entity.Tenants.Add(new EntityTenant(api.PageInfo, entity.Name, entity.GetColumn("colName").ActualFullName, // Get col by Alias but supply ActualFullName "parameterId" // Tenant parameter ));
Filter dropdowns
entity.FilterObjectType = DataObjectType.Table; // Table, View, Function, Procedure, etc. entity.FilterDbName = "FilterObjectName"; // or custom SQL: entity.FilterObjectType = DataObjectType.SqlStmt; entity.FilterSqlStmt = "SELECT etc...";
Joins
See all config joins
// Build the join string for display string joinString = ""; // All config joins; for report joins, use report.Joins foreach (Join join in api.Joins.OrderByDescending(x => x.Weight)) // Order by weight { foreach (JoinColumn col in join.JoinColumns) { joinString += string.Format("{0} {1} {2}{3}\n", col.FromColumn.FullKeyName, join.JoinText, col.ToColumn.FullKeyName, join.RelationType == 1 ? "(s)" : "" // 1-to-Many ); } if (join.Weight > 0) joinString += ("Weight: " + join.Weight + "\n"); }
Get specific join
Join join = api.Joins.GetItem("fromEntity", "toEntity", false);
Create a new join
NoteFor creation of Advanced Joins, see Advanced Joins.
Entity fromEntity = api.Entities.GetEntity("fromName"); Entity toEntity = api.Entities.GetEntity("toName"); Join newJoin = new Join(api.PageInfo) { EntityFromName = fromEntity.Name, EntityToName = toEntity.Name, Type = (int)JoinType.Inner, RelationType = 0, // 0: One-to-One, 1: One-to-Many Weight = 0 };
// Add key columns
newJoin.JoinColumns.Add(new JoinColumn(
new KeyColumn(fromEntity.Name, fromEntity.GetColumn("fromColName").ActualFullName),
new KeyColumn(toEntity.Name, toEntity.GetColumn("toColName").ActualFullName)
));
// Add to the config; for reports, use report.Joins.Add() api.Joins.Add(newJoin); // If there is an active report, recreate the joins report.CreateJoins();
Custom Functions
Get a specific function
UdfFunction function = api.CustomFunctions.GetItem("functionName");
Create a new function
UdfFunction newFunction = new UdfFunction(api.PageInfo) { Name = "functionName", AvailableIn = UdfFunctionAvailableType.Formula, // Custom or filter function
ArgumentsJson = "[{'Name':'argName','Required':true,'Description':'desc'}]", Language = CodeLanguage.CSharp.ToString(), ProgramCode = "Code();" }; // Add any references and namespaces newFunction.Namespaces.Add("Program.Namespace"); newFunction.References.Add("Reference.dll"); // Add to the config api.CustomFunctions.Add(newFunction);
Custom Aggregate Functions
Get a specific function
UdfFunction function = api.CustomFunctions.GetItem("functionName");
Create a new function
var newCustomAgg = new UdfFunction(); newCustomAgg.AvailableIn = UdfFunctionAvailableType.CustomAggregate; newCustomAgg.Language = "VB"; newCustomAgg.Name = "APICustomAgg"; newCustomAgg.Namespaces.Add("WebReports.Api.Common"); newCustomAgg.Category = "CustomAggs"; newCustomAgg.ProgramCode = @" Public Class MyCustomAggregator Inherits ICustomAggregator Private count Public Sub AddValue(ByVal sessionInfo As SessionInfo, ByVal value As Object, ParamArray args As Object()) count = count + 1 End Sub Public Function Result(ByVal sessionInfo As SessionInfo, ParamArray args As Object()) As Object Return count End Function End Class"; newCustomAgg.ArgumentsJson = "[{\"Name\":\"dataToAggregate\",\"Required\":true,\"Description\":\"\"},{\"Name\":\"recordLevel\",\"Required\":false,\"Description\":\"\"}]"; Common.Api.SetupData.Functions.Add(newCustomAgg);
Server Events
Get a specific server event
ServerEvent serverEvent = api.ServerEvents.GetByName("eventName");
Create a new server event
ServerEvent newEvent = new ServerEvent(api.PageInfo) { Name = "eventName", EventType = ServerEventType.OnReportExecuteStart, // Global event, or "None" }; // Custom code newEvent.ServerCode.CustomCode.Language = CodeLanguage.CSharp; newEvent.ServerCode.CustomCode.ProgramCode = "Code();";
//Add a namespace
newEvent.ServerCode.CustomCode.Namespaces.Add("System.IO");
// Code from data source newEvent.ServerCode.DataSourceId = api.DataSources.GetDataSource("eventsAssembly").Id; newEvent.ServerCode.FunctionName = "functionName"; // Add to config api.ServerEvents.Add(newEvent); // Add to a report (must be in config) report.ServerEvents.Add(new ReportServerEvent(api.PageInfo) { EventType = ServerEventType.OnDataCombined, EventId = api.ServerEvents.GetByName("eventName").Id });
Storage Management Schema
Update reports to the current Storage Management schema when changing versions. This is the same as clicking the Update Reports button in the Admin Console.
Api api = new Api("appPath");
String updateResults = (new WebReports.Api.ReportMgmt.UpdateReportsUtility(api.PageInfo)).RewriteAllReports();
Scheduling
NoteUse of the
NodaTime
library is required beginning with v2019.1. More information is available in the Time Zone Calculation Enhancements in v2019.1 article.
View schedule list
List<Exception> exceptions; // Build the job list string string jobList = ""; foreach (List<JobInfo> schedule in api.ReportScheduler.GetJobList(out exceptions)) { foreach (JobInfo job in schedule.OrderBy(x => x.NextExecuteDate).ThenBy(x => x.Name)) { jobList += string.Format("Job '{0}' for report '{1}' ", job.Name, api.ReportScheduler.GetReportScheduleInfoByJobId(job.JobId.ToString()).ReportBaseName ); switch (job.Status) { case JobStatus.Completed: jobList += string.Format("ran on {0}, at host {1}.\n", job.LastExecuteDate.ToString("MMM d hh:mm tt"), api.ReportScheduler.GetHost(api.ReportScheduler.GetHostIdxForJob(job.JobId)) ); break; case JobStatus.Ready: jobList += string.Format("ready to run on {0}.\n", job.NextExecuteDate.ToString("MMM d hh:mm tt") ); break; case JobStatus.Deleted: case JobStatus.Removed: case JobStatus.Abended: case JobStatus.UserAbort: jobList += string.Format("ended. Last run on {0}, at host {1}.\n", job.LastExecuteDate.ToString("MMM d hh:mm tt"), api.ReportScheduler.GetHost(api.ReportScheduler.GetHostIdxForJob(job.JobId)) ); break; default: jobList += string.Format("status unknown.\n"); break; } } }
Create an immediate schedule (basic options)
NoteSet the Api object's Active Report before creating the schedule. The active report is the report that is scheduled.
using NodaTime; ... // Run-once, immediately save to disk string jobId; // Use to retrieve schedule info later for editing int hostIdx; // Assigned execution host id ReportScheduleInfo newSchedule = new ReportScheduleInfoOnce() { ScheduleName = "Immediate Schedule", // Schedule name ReportType = wrReportType.Advanced, // Report type RangeStartDate = new LocalDate(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day), // Start date ScheduleTime = new LocalTime(DateTime.Now.Hour, DateTime.Now.Minute), // Start time SendReportInEmail = false // Email or save }; // Send to the scheduler; wrap in try/catch to handle exceptions try { api.ReportScheduler.AddReport( new ReportSchedule(api.PageInfo) { ScheduleInfo = newSchedule }, out jobId, out hostIdx); } catch (Exception) { }
Recurring schedules (additional options)
Daily
NoteSet the Api object's Active Report before creating the schedule. The active report is the report that is scheduled.
using NodaTime; ... ReportScheduleInfo newSchedule = new ReportScheduleInfoDaily() { ... // Include basic options // Range of recurrence, every N days, or every weekday DailyPattern = ReportScheduleInfo.DailyPatternType.EveryNDays, EveryNDays = 2, // N days // End date (optional): RangeEndDate = new LocalDate(2017, 12, 25), // End on a specific date RangeNOccurences = 10, // Or end after N occurrences // intraday recurrence (optional): RepeatEvery = true, // Enable intraday recurrence RepeatEveryHours = 4, // Repeat every N hours RepeatEveryMinutes = 0, // And N minutes RepeatEveryEndTime = new TimeSpan(DateTime.Parse("12:00 PM").Ticks) // Optional end time }
Weekly
NoteSet the Api object's Active Report before creating the schedule. The active report is the report that is scheduled.
ReportScheduleInfo newSchedule = new ReportScheduleInfoWeekly() { ... // Include basic options ... // Optional end date, optional intraday recurrence EveryNWeeks = 1, // Every N weeks // On these days: Sun Mon Tues Wed Thu Fri Sat IsDayOfWeek = new bool[] { false, true, false, false, true, false, false } }
Monthly
ReportScheduleInfo newSchedule = new ReportScheduleInfoMonthly() { ... // Include basic options ... // Optional end date, optional intraday recurrence // Specific or relative day pattern MonthlyPattern = ReportScheduleInfo.MonthlyPatternType.SpecificDayOfMonth, // Specific: day X of every N months SpecificDayOfMonth = 7, // Day of the month SpecificEveryNMonths = 2, // Every N months // Relative: the Xth day-of-week of every N months RelativeWeekOfMonth = ReportScheduleInfo.WeekOfMonthType.First, // Week of month RelativeDayOfWeek = ReportScheduleInfo.DayOfWeekType.Weekday, // Day of week RelativeEveryNMonths = 2 // Every N months }
NoteSet the Api object's Active Report before creating the schedule. The active report is the report that is scheduled.
Yearly
ReportScheduleInfo newSchedule = new ReportScheduleInfoYearly() { ... // Include basic options ... // Optional end date, optional intraday recurrence // Specific or relative day pattern YearlyPattern = ReportScheduleInfo.YearlyPatternType.SpecificDayOfYear, // Specific: Month/Day of every year SpecificMonthOfYear = 3, // Month of the year SpecificDayOfMonth = 15, // Day of the month // Relative: the Xth day-of-week for month N RelativeWeekOfMonth = ReportScheduleInfo.WeekOfMonthType.Last, // Week of month RelativeDayOfWeek = ReportScheduleInfo.DayOfWeekType.Friday, // Day of week RelativeMonthOfYear = 3 // Month N }
Email job
newSchedule.SendReportInEmail = true; // Enable email newSchedule.EmailSubject = "Subject Text"; // Email subject newSchedule.EmailBody = "Hello World!"; // Email body newSchedule.EmailToList.Add("email@company.com"); // To addresses // newSchedule.EmailCCList.Add(); // CC addresses // newSchedule.EmailBccList.Add(); // BCC addresses
Batch email
// Batch addresses entity (must be in the batch report) Entity batchAddresses = report.Entities.GetEntity("entityName"); newSchedule.IsBatchReport = true; // Enable batch newSchedule.BatchEmailToList.Add("supervisor@example.com"); // Summary recipients // newSchedule.BatchEmailCcList.Add(); // Summary cc recipients newSchedule.BatchEntity = batchAddresses.Name; // Email address object newSchedule.BatchField = batchAddresses.GetColumn("Email").Name; // Email address field newSchedule.IncludeReportAttachment = true; // Include the report
Access existing schedule by jobId
ReportScheduleInfo schedule = api.ReportScheduler.GetReportScheduleInfoByJobId("jobId");
Update an existing schedule
api.ReportScheduler.UpdateExistingSchedule(newSchedule, "jobIdToUpdate");
Delete an existing schedule
api.ReportScheduler.DeleteSchedulerJob("jobIdToDelete");
Managing Files and Folders
Initialize the manager class for the type of folder or storage management in use
// Storage Management - use for all versions v2020.1+
ReportMgmtBase manager = api.ReportManagement;
// File System - legacy use only ReportMgmtFileSystem manager = new ReportMgmtFileSystem(api.PageInfo); // Database - legacy use only ReportMgmtMethod manager = new ReportMgmtMethod(api.PageInfo); // Cloud drive - legacy use only ReportMgmtCloud manager = new ReportMgmtCloud(api.PageInfo);
View the full reports tree
XmlDocument tree = new XmlDocument() { InnerXml = manager.GetReportListXml() };
View themes list by type
List<string> evThemes = manager.GetThemeList(ReportTheme.ReportThemeType.ExpressView.ToString());
Get a specific theme (class depends on theme type)
ExpressViewTheme evTheme = (ExpressViewTheme)ReportTheme.GetTheme( api.PageInfo, ReportTheme.ReportThemeType.ExpressView, "themeName");
View list of templates
List<string> templates = manager.GetTemplateList();
Add a new folder
manager.AddFolder("parentFolder", "newFolderName");
Move or rename a folder
manager.RenameFolder("oldPath", "newPath");
Move or rename a report
manager.RenameReport("oldPath", "newPath");
Duplicate an existing report
api.ReportObjectFactory.Copy("reportName", "newName");
Save a new report to disk
api.ReportObjectFactory.Copy(report, "reportName", null);