Exago Logo
Search
Generic filters
Exact matches only

.NET API General Reference

Note

This 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.

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 connecting to a .NET Assembly Data Source, 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

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.

Note

Variable 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}nt{1}nt{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.

Caution

The .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       = "AGreatParameterName", // No spaces allowed
  DataType = (int)DataType.String,
  Value    = "foobar"
});

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

Note

This 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

Tip

Set the Id property before the DbName.

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

Note

For 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

				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();
String updateResults = (new WebReports.Api.ReportMgmt.UpdateReportsUtility(api.PageInfo)).RewriteAllReports();

Scheduling

Note

Use 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)

Note

Set 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

Note

Set 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

  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

Note

Set 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
}

Note

Set 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 protected]"); // 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("[email protected]");       // 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);
Was this article helpful?
0 out of 5 stars
5 Stars 0%
4 Stars 0%
3 Stars 0%
2 Stars 0%
1 Stars 0%
How can we improve this article?
Please submit the reason for your vote so that we can improve the article.
Table of Contents