Files to look at:
- ConnectionProviderExtensions.cs (VB: ConnectionProviderExtensions.vb)
- MainForm.cs (VB: MainForm.vb)
- Program.cs (VB: Program.vb)
- ReportViewerForm.cs (VB: ReportViewerForm.vb)
- SchedulerJobResultsForm.cs (VB: SchedulerJobResultsForm.vb)
- SchedulerJobViewerForm.cs (VB: SchedulerJobViewerForm.vb)
- WaitForm1.cs (VB: WaitForm1.vb)
This example illustrates how to enable a client-side WinForms application to access the Report Server and remotely manage scheduled jobs.
For this application to be able to access the Report Server, make sure that the ServerAddress field in the application's MainForm.cs file matches the Site URL specified in your Report Server settings (it is set to "http://localhost:83" by default).
To log into the Report Server, the application uses the Guest account by default, so it is required that this user is active (you can check this in the User Accounts panel).
On running the application, the main form displays a complete list of currently scheduled tasks (jobs). After selecting a task, you can do one of the following.
- To manage a specific task, click "Show Scheduled Task Parameters". On the invoked form, you can create a new task, as well as update, delete or execute the selected task.
- To inspect the logs stored for a task, click "Show Scheduled Task Results". On the invoked form, you can view the history of task executions along with results of each execution.
The API that this application uses to access the Report Server is related to the following public namespaces.
- DevExpress.ReportServer.ServiceModel.ConnectionProviders
- DevExpress.ReportServer.ServiceModel.Client
- DevExpress.ReportServer.ServiceModel.DataContracts
To learn more about the corresponding infrastructure, please consult with the DevExpress product documentation.
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using DevExpress.ReportServer.ServiceModel.Client;
using DevExpress.ReportServer.ServiceModel.ConnectionProviders;
using System;
using System.Threading.Tasks;
namespace ScheduledTasksAPIClientDemo {
public static class ConnectionProviderExtensions {
public static Task<T> DoWithScheduledJobAsync<T>(this ConnectionProvider serverConnection, Func<IReportServerClient, Task<T>> func) {
return serverConnection
.ConnectAsync()
.ContinueWith(taskFunc => {
IReportServerClient client = taskFunc.Result;
return func(client);
})
.Unwrap();
}
public static Task DoWithScheduledJobAsync(this ConnectionProvider serverConnection, Func<IReportServerClient, Task> func) {
return serverConnection
.ConnectAsync()
.ContinueWith(task => func(task.Result))
.Unwrap();
}
}
}
C#using DevExpress.ReportServer.ServiceModel.ConnectionProviders;
using DevExpress.ReportServer.ServiceModel.DataContracts;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ScheduledTasksAPIClientDemo {
public partial class MainForm : Form {
// Specifies the Report Server address.
public const string ServerAddress = "http://localhost:83";
// Specifies the connection provider for accessing the Report Server.
// The Guest connection provider is used by default.
// To be able to run the application, make sure that the Guest account
// is activated in the Report Server administrative panel.
readonly ConnectionProvider serverConnection = new WindowsUserConnectionProvider(ServerAddress);
public MainForm() {
InitializeComponent();
}
// The following method obtains the list of all scheduled jobs from the server
// and displays this list in a grid control.
void MainForm_Load(object sender, EventArgs e) {
splashScreenManager1.ShowWaitForm();
serverConnection.DoWithScheduledJobAsync(x => x.GetScheduledJobsAsync(null))
.ContinueWith(taskFunc => {
splashScreenManager1.CloseWaitForm();
if (taskFunc.IsFaulted) {
MessageBox.Show(taskFunc.Exception.Flatten().InnerException.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else {
FillScheduledJobListBox(taskFunc.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
void FillScheduledJobListBox(IEnumerable<ScheduledJobCatalogItemDto> scheduledJobs) {
scheduledJobsGrid.DataSource = scheduledJobs;
scheduledJobsView.BestFitColumns();
}
// The following method displays the Scheduler Task Viewer form
// that enables you to inspect and manage a selected task.
void showScheduledJobButton_Click(object sender, EventArgs e) {
var selectedId = scheduledJobsView.GetFocusedRowCellValue("Id") as int?;
if (selectedId.HasValue) {
var form = new SchedulerJobViewerForm(selectedId.Value, serverConnection) { Owner = this };
form.ShowDialog();
}
}
// The following method displays the Scheduler Job Results form
// that lists all documents generated by a selected task
// and enables you to view a specific document.
private void showScheduledJobResultsButton_Click(object sender, EventArgs e) {
var selectedId = scheduledJobsView.GetFocusedRowCellValue("Id") as int?;
var selectedName = scheduledJobsView.GetFocusedRowCellValue("Name") as string;
if (selectedId.HasValue) {
var form = new SchedulerJobResultsForm(selectedId.Value, selectedName, serverConnection) { Owner = this };
form.ShowDialog();
}
}
private void scheduledJobsView_FocusedRowChanged(object sender, DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs e) {
showScheduledJobButton.Enabled = scheduledJobsView.SelectedRowsCount > 0;
showScheduledJobResultsButton.Enabled = scheduledJobsView.SelectedRowsCount > 0;
}
}
}
C#using System;
using System.Windows.Forms;
namespace ScheduledTasksAPIClientDemo {
static class Program {
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
C#using DevExpress.ReportServer.Printing;
using DevExpress.ReportServer.ServiceModel.DataContracts;
using System.Windows.Forms;
namespace ScheduledTasksAPIClientDemo {
public partial class ReportViewerForm : Form {
public ReportViewerForm(int reportId) {
InitializeComponent();
remoteDocumentSource1.ServiceUri = MainForm.ServerAddress;
remoteDocumentSource1.AuthenticationType = AuthenticationType.Guest;
remoteDocumentSource1.ReportIdentity = new GeneratedReportIdentity(reportId);
remoteDocumentSource1.CreateDocument();
}
}
}
C#using DevExpress.ReportServer.ServiceModel.ConnectionProviders;
using DevExpress.ReportServer.ServiceModel.DataContracts;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ScheduledTasksAPIClientDemo {
public partial class SchedulerJobResultsForm : Form {
#region inner classes
class Info {
public string Name { get; set; }
public object Value { get; set; }
}
#endregion
readonly ConnectionProvider serverConnection;
readonly int scheduledJobId;
public SchedulerJobResultsForm(int scheduledJobId, string scheduledJobName, ConnectionProvider serverConnection) {
InitializeComponent();
this.serverConnection = serverConnection;
this.scheduledJobId = scheduledJobId;
this.id.Text = string.Format("{0}", scheduledJobId);
this.scheduledJobName.Text = scheduledJobName;
}
// The following code obtains the logs corresponding to a selected scheduled job from the server
// for the period of 100 days prior to the current date
// and displays the total number of obtained logs.
private void SchedulerJobResults_Load(object sender, EventArgs e) {
splashScreenManager1.ShowWaitForm();
serverConnection.DoWithScheduledJobAsync(x => x.GetScheduledJobLogsAsync(scheduledJobId,
new DataPaginationByDate() {
From = DateTime.Now - TimeSpan.FromDays(100),
Interval = TimeSpan.FromDays(100)
}, null))
.ContinueWith(taskFunc => {
splashScreenManager1.CloseWaitForm();
if (taskFunc.IsFaulted) {
MessageBox.Show(taskFunc.Exception.GetBaseException().Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else {
FillScheduledJobLogs(taskFunc.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith((taskFunc) => {
return serverConnection.DoWithScheduledJobAsync(x => x.GetScheduledJobLogsCountAsync(scheduledJobId, null));
})
.Unwrap()
.ContinueWith(taskFunc => {
logsLabel.Text = string.Format("Logs count: {0}", taskFunc.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
// The following method populates a grid control with a list
// of job executions and the dates on which they were started.
void FillScheduledJobLogs(IEnumerable<ScheduledJobLogDto> scheduledJobLogs) {
jobLogsView.GridControl.DataSource = scheduledJobLogs;
}
// The following code displays information about the last 100 results of a job's execution.
// This information includes the date and time when the result was obtained,
// as well as the status or result of its execution and the total number of results.
private void jobLogsView_FocusedRowChanged(object sender, DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs e) {
jobResultsGrid.DataSource = null;
resultInfoGrid.DataSource = null;
var selectedId = jobLogsView.GetFocusedRowCellValue("Id") as int?;
if (!selectedId.HasValue) {
return;
}
splashScreenManager1.ShowWaitForm();
serverConnection.DoWithScheduledJobAsync(x => x.GetScheduledJobResultsAsync(selectedId.Value,
new DataPaginationByCount() {
Offset = 0,
Count = 100
}, null))
.ContinueWith(taskFunc => {
splashScreenManager1.CloseWaitForm();
if (taskFunc.IsFaulted) {
MessageBox.Show(taskFunc.Exception.GetBaseException().Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else {
FillScheduledJobResults(taskFunc.Result, selectedId.Value);
}
}, TaskScheduler.FromCurrentSynchronizationContext())
.ContinueWith((taskFunc) => {
return serverConnection.DoWithScheduledJobAsync(x => x.GetScheduledJobResultsCountAsync(selectedId.Value, null));
})
.Unwrap()
.ContinueWith(taskFunc => {
resultsLabel.Text = string.Format("Results count: {0}", taskFunc.Result);
}, TaskScheduler.FromCurrentSynchronizationContext());
}
void FillScheduledJobResults(IEnumerable<ScheduledJobResultCatalogItemDto> scheduledJobResults, int scheduledJobLogId) {
jobResultsView.GridControl.DataSource = scheduledJobResults;
}
// The following code displays information about the selected job execution result.
// This information includes a list of email subscribers,
// parameter values at the moment of execution, and (when applicable)
// the reason why the task execution failed.
private void jobResultsView_FocusedRowChanged(object sender, DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs e) {
previewDocumentButton.Enabled = false;
resultInfoGrid.DataSource = null;
if (jobResultsView.SelectedRowsCount == 0) {
return;
}
var selectedId = jobResultsView.GetFocusedRowCellValue("Id") as int?;
if (!selectedId.HasValue) {
return;
}
var status = jobResultsView.GetFocusedRowCellValue("Status") as JobResultStatus?;
previewDocumentButton.Enabled = status.HasValue && status.Value == JobResultStatus.Success;
splashScreenManager1.ShowWaitForm();
serverConnection.DoWithScheduledJobAsync(x => x.GetScheduledJobResultAsync(selectedId.Value, null))
.ContinueWith(taskFunc => {
splashScreenManager1.CloseWaitForm();
if (taskFunc.IsFaulted) {
MessageBox.Show(taskFunc.Exception.GetBaseException().Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else {
FillScheduledJobResultInfo(taskFunc.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
void FillScheduledJobResultInfo(ScheduledJobResultDto scheduledJobResult) {
var infos = new List<Info>();
infos.Add(new Info { Name = "Recipients", Value = scheduledJobResult.Recipients });
infos.Add(new Info { Name = "Reason", Value = scheduledJobResult.Message });
infos.Add(new Info { Name = "Parameters", Value = scheduledJobResult.ExecutionParameters });
resultInfoGrid.DataSource = infos;
resultInfoView.BestFitColumns();
}
// The following code invokes a Print Preview form displaying
// the report document created by a selected task.
private void previewDocumentButton_Click(object sender, EventArgs e) {
if (jobResultsView.SelectedRowsCount == 0) {
return;
}
var selectedId = jobResultsView.GetFocusedRowCellValue("Id") as int?;
if (!selectedId.HasValue) {
return;
}
ReportViewerForm form = new ReportViewerForm(selectedId.Value) { Owner = this };
form.ShowDialog();
}
}
}
C#using DevExpress.ReportServer.ServiceModel.ConnectionProviders;
using DevExpress.ReportServer.ServiceModel.DataContracts;
using DevExpress.XtraScheduler;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ScheduledTasksAPIClientDemo {
public partial class SchedulerJobViewerForm : Form {
#region inner classes
class Info {
public string Name { get; set; }
public object Value { get; set; }
}
class Parameter {
public string Name { get; set; }
public SchedulerParametersSource Source { get; set; }
public object Value { get; set; }
}
#endregion
readonly ConnectionProvider serverConnection;
readonly int scheduledJobId;
public SchedulerJobViewerForm(int scheduledJobId, ConnectionProvider serverConnection) {
InitializeComponent();
this.serverConnection = serverConnection;
this.scheduledJobId = scheduledJobId;
}
// The following code obtains information about a specific scheduled job from the server
// and enables you to remotely manage scheduled jobs on the client.
// Please note that managing jobs requires that appropriate access permissions are attributed
// to the user account under which this application is connected to the Server.
private void SchedulerJobViewerForm_Load(object sender, EventArgs e) {
serverConnection.DoWithScheduledJobAsync(x => x.GetScheduledJobAsync(scheduledJobId, null))
.ContinueWith(taskFunc => {
if (taskFunc.IsFaulted) {
MessageBox.Show(taskFunc.Exception.GetBaseException().Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); //
}
else {
FillScheduledJob(taskFunc.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
void FillScheduledJob(ScheduledJobDto scheduledJob) {
id.Text = string.Format("{0}", scheduledJob.Id);
scheduledJobName.Text = scheduledJob.Name;
scheduledJobEnabled.Checked = scheduledJob.Enabled;
scheduledJobStartDate.DateTime = scheduledJob.StartDate.ToLocalTime();
reportId.Text = string.Format("{0}", scheduledJob.ReportId);
FillRecurrencyInfo(scheduledJob);
FillParametersBinding(scheduledJob);
FillParameters(scheduledJob);
FillExternalSubscribers(scheduledJob);
FillExportToShared(scheduledJob);
}
#region Appointment
void FillRecurrencyInfo(ScheduledJobDto scheduledJob) {
recurrencyInfo.Text = string.Empty;
var appointment = CreateAppointment(scheduledJob);
if (appointment == null) {
return;
}
var culture = Thread.CurrentThread.CurrentUICulture;
var infos = new List<Info>();
infos.Add(new Info { Name = "Description", Value = RecurrenceInfo.GetDescription(appointment, culture.DateTimeFormat.FirstDayOfWeek) });
infos.Add(new Info { Name = "Next start", Value = GetNextDateDisplayText(appointment) });
recurrencyInfoGrid.DataSource = infos;
recurrencyInfoView.BestFitColumns();
}
Appointment CreateAppointment(ScheduledJobDto scheduledJob) {
if (string.IsNullOrEmpty(scheduledJob.SerializedRecurrenceInfo)) {
return null;
}
var appointment = DevExpress.XtraScheduler.Compatibility.StaticAppointmentFactory.CreateAppointment(AppointmentType.Pattern);
appointment.Start = scheduledJob.StartDate.ToLocalTime();
appointment.RecurrenceInfo.FromXml(scheduledJob.SerializedRecurrenceInfo);
appointment.RecurrenceInfo.Start = appointment.Start;
return appointment;
}
string GetNextDateDisplayText(Appointment appointment) {
const string ScheduledJobExpired = "Never (expired)";
const string ScheduledJobExpiredFormat = "Never (expired on {0:d})";
var calculator = OccurrenceCalculator.CreateInstance(appointment.RecurrenceInfo);
var nextDate = calculator.FindNextOccurrenceTimeAfter(DateTime.Now, appointment);
if (nextDate != DateTime.MaxValue) {
return nextDate.ToString("g");
}
else {
var lastDate = GetLastDate(appointment, calculator);
return lastDate != null
? string.Format(ScheduledJobExpiredFormat, lastDate)
: ScheduledJobExpired;
}
}
DateTime? GetLastDate(Appointment appointment, OccurrenceCalculator calculator) {
var index = calculator.CalcLastOccurrenceIndex(appointment);
return index >= 0
? (DateTime?)appointment.GetOccurrence(index).Start
: null;
}
#endregion
#region Parameters Binding
void FillParametersBinding(ScheduledJobDto scheduledJob) {
var infos = new List<Info>();
if (scheduledJob.SchedulerParameters.Binding != null) {
infos.Add(new Info { Name = "Data Model (id)", Value = scheduledJob.SchedulerParameters.Binding.DataModelId });
infos.Add(new Info { Name = "Data Member", Value = scheduledJob.SchedulerParameters.Binding.DataMember });
infos.Add(new Info { Name = "Email Field", Value = scheduledJob.SchedulerParameters.Binding.EmailField });
infos.Add(new Info { Name = "Recipient Name Field", Value = scheduledJob.SchedulerParameters.Binding.DisplayNameField });
parametersBindingGrid.DataSource = infos;
parametersBindingView.BestFitColumns();
}
}
#endregion
#region Report Parameters
void FillParameters(ScheduledJobDto scheduledJob) {
var parameters = new List<Parameter>();
foreach (var item in scheduledJob.SchedulerParameters.Parameters) {
parameters.Add(new Parameter() { Name = item.Key, Source = item.Value.Source, Value = item.Value.Value });
}
reportParametersGrid.DataSource = parameters;
reportParametersView.BestFitColumns();
}
#endregion
#region External Subscribers
void FillExternalSubscribers(ScheduledJobDto scheduledJob) {
externalSubscribers.Text = scheduledJob.ExternalSubscribers;
}
#endregion
#region Export to Shared Folder
void FillExportToShared(ScheduledJobDto scheduledJob) {
exportToSharedFolder.Text = scheduledJob.ExportToSharedFolder;
}
#endregion
#region Delete Task
private void btnDelete_Click(object sender, EventArgs e) {
serverConnection
.DoWithScheduledJobAsync(x => x.DeleteScheduledJobAsync(scheduledJobId, null))
.ContinueWith(
taskFunc => MessageBox.Show(taskFunc.Exception.GetBaseException().Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error),
TaskContinuationOptions.OnlyOnFaulted);
}
#endregion
#region Update Task
private void btnUpdate_Click(object sender, EventArgs e) {
serverConnection
.DoWithScheduledJobAsync(x => x.GetScheduledJobAsync(scheduledJobId, null))
.ContinueWith(taskFunc => {
var scheduledJob = taskFunc.Result;
scheduledJob.Name = scheduledJobName.Text;
scheduledJob.Enabled = scheduledJobEnabled.Checked;
scheduledJob.StartDate = scheduledJobStartDate.DateTime;
scheduledJob.ExternalSubscribers = externalSubscribers.Text;
scheduledJob.ExportToSharedFolder = exportToSharedFolder.Text;
int selectedReportId;
if (int.TryParse(reportId.Text, out selectedReportId)) {
scheduledJob.ReportId = selectedReportId;
}
else {
scheduledJob.ReportId = null;
}
return serverConnection.DoWithScheduledJobAsync(x => x.UpdateScheduledJobAsync(scheduledJob, null));
})
.Unwrap()
.ContinueWith(taskFunc => MessageBox.Show(taskFunc.Exception.GetBaseException().Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
, new CancellationToken(), TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
}
#endregion
#region Create Task
private void btnCreate_Click(object sender, EventArgs e) {
var scheduledJob = new ScheduledJobDto();
scheduledJob.TaskMode = ScheduledTaskMode.BillingStatement;
scheduledJob.Name = scheduledJobName.Text;
scheduledJob.Enabled = scheduledJobEnabled.Checked;
scheduledJob.StartDate = scheduledJobStartDate.DateTime.ToUniversalTime();
using (var apt = DevExpress.XtraScheduler.Compatibility.StaticAppointmentFactory.CreateAppointment(AppointmentType.Pattern)) {
apt.RecurrenceInfo.Type = RecurrenceType.Daily;
apt.RecurrenceInfo.Start = scheduledJob.StartDate;
apt.RecurrenceInfo.WeekDays = WeekDays.WorkDays;
scheduledJob.SerializedRecurrenceInfo = apt.RecurrenceInfo.ToXml();
}
scheduledJob.SchedulerParameters = new SchedulerParameters() {
Binding = new ParametersBinding() {
DataModelId = 1,
DataMember = "vwEmployees",
EmailField = "Email",
DisplayNameField = "DisplayName"
}
};
scheduledJob.InternalSubscribers = null;
scheduledJob.ExternalSubscribers = externalSubscribers.Text;
scheduledJob.ExportToSharedFolder = exportToSharedFolder.Text;
int selectedReportId;
if (int.TryParse(reportId.Text, out selectedReportId)) {
scheduledJob.ReportId = selectedReportId;
}
else {
scheduledJob.ReportId = null;
}
serverConnection
.DoWithScheduledJobAsync(x => x.CreateScheduledJobAsync(scheduledJob, null))
.ContinueWith(taskFunc => {
if (taskFunc.IsFaulted) {
MessageBox.Show(taskFunc.Exception.GetBaseException().Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else {
id.Text = taskFunc.Result.ToString();
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
#endregion
private void btnExecute_Click(object sender, EventArgs e) {
serverConnection.DoWithScheduledJobAsync(x => x.ExecuteJobAsync(scheduledJobId, null, null));
}
}
}
C#// Developer Express Code Central Example:
// How to get the list of available reports, export to PDF and display a report preview in a Windows Forms application
//
// The sample demonstrates how to use the Report Server WCF API in a Windows Forms
// application.
//
// You can find sample updates and versions for different programming languages here:
// http://www.devexpress.com/example=E5062
// Developer Express Code Central Example:
// How to connect to a Report Server from a Windows Forms application
//
// The sample demonstrates how to use the Report Server WCF API in a Windows Forms
// application.
//
// You can find sample updates and versions for different programming languages here:
// http://www.devexpress.com/example=E5062
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraWaitForm;
namespace ScheduledTasksAPIClientDemo
{
public partial class WaitForm1 : WaitForm
{
public WaitForm1()
{
InitializeComponent();
this.progressPanel1.AutoHeight = true;
}
#region Overrides
public override void SetCaption(string caption)
{
base.SetCaption(caption);
this.progressPanel1.Caption = caption;
}
public override void SetDescription(string description)
{
base.SetDescription(description);
this.progressPanel1.Description = description;
}
public override void ProcessCommand(Enum cmd, object arg)
{
base.ProcessCommand(cmd, arg);
}
#endregion
}
}