Skip to main content
A newer version of this page is available. .

Implement a Report Storage

  • 5 minutes to read

This document describes how to store reports in the Web Report Designer application and contains server-side report storage examples.

Overview

The Web Report Designer requires storage (a database, file system, cloud, etc.) to save and load reports. You should explicitly implement a report storage class to store reports and register this storage in your application.

How to Implement a Custom Report Storage

Add a new class inherited from the abstract ReportStorageWebExtension class and implement the following methods:

  • IsValidUrl - Determines whether the url (report identifier) passed to the current report storage is valid. You can implement your own logic to prohibit identifiers that contain spaces or other specific characters. When the user saves a modified report, Web Report Designer calls this method before the CanSetData and SeData methods. When the user opens a report, Web Report Designer calls this method before the CanSetData and SeData methods.

  • CanSetData - Determines whether a report with the specified identifier can be saved. Add a custom logic and return false for reports that should be read-only. This method is called only for valid identifiers (if the IsValidUrl method returns true) before the SetData method.

  • SetData - Saves the specified report to the report storage with the specified identifier (that is, saves existing reports only). This method is called after the IsValidUrl and CanSetData methods.

  • SetNewData - Saves a new report. Uses a new identifier to store the specified report. You can validate and correct the specified identifier in the SetNewData method implementation and return the resulting identifier to save the report.

  • GetData - Returns a dictionary that contains report identifiers and display names. This method is called when running the Report Designer, before the Open Report and Save Report dialogs and after a new report is saved.

  • GetUrls - Returns a dictionary that contains existing report identifiers and display names. This method is called when the Report Designer runs, before the Open Report and Save Report dialogs, and after a new report is saved.

The following table shows the method call sequence:

Action Call Sequence
Save a newly created report GetUrls -> invoke the Save Report dialog -> SetNewData
Open a report GetUrls -> invoke the Open Report dialog -> IsValidUrl -> GetData
Save a modified report IsValidUrl -> CanSetData -> SetData

Register the report storage as a service in the ConfigureServices method:

using DevExpress.XtraReports.Web.Extensions;
//... 

    public class Startup {
        // ...

        public void ConfigureServices(IServiceCollection services) {
            // ...
            services.AddScoped<ReportStorageWebExtension, ReportStorageWebExtension1>(); 
            // ...  
        }
    // ...
    }    

Report Storage Examples

The following code snippet contains an example of report storage that stores reports in a file system:

Note

A project created with the DevExpress template and uses report storage to store reports in a file system is described in the Create an ASP.NET Core Application with a Report Designer topic.

Show content
using DevExpress.XtraReports.UI;
using Microsoft.AspNetCore.Hosting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace DXWebApplication1.Services
{
    public class ReportStorageWebExtension1 : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
    {
        readonly string ReportDirectory;
        const string FileExtension = ".repx";
        public ReportStorageWebExtension1(IWebHostEnvironment env) {
            ReportDirectory = Path.Combine(env.ContentRootPath, "Reports");
            if (!Directory.Exists(ReportDirectory)) {
                Directory.CreateDirectory(ReportDirectory);
            }
        }

        public override bool CanSetData(string url) {
            // Determines whether or not it is possible to store a report by a given URL. 
            // For instance, make the CanSetData method return false for reports that should be read-only in your storage. 
            // This method is called only for valid URLs (i.e., if the IsValidUrl method returned true) before the SetData method is called.

            return true;
        }

        public override bool IsValidUrl(string url) {
            // Determines whether or not the URL passed to the current Report Storage is valid. 
            // For instance, implement your own logic to prohibit URLs that contain white spaces or some other special characters. 
            // This method is called before the CanSetData and GetData methods.

            return true;
        }

        public override byte[] GetData(string url) {
            // Returns report layout data stored in a Report Storage using the specified URL. 
            // This method is called only for valid URLs after the IsValidUrl method is called.
            try {
                if (Directory.EnumerateFiles(ReportDirectory).Select(Path.GetFileNameWithoutExtension).Contains(url))
                {
                    return File.ReadAllBytes(Path.Combine(ReportDirectory, url + FileExtension));
                }
                throw new DevExpress.XtraReports.Web.ClientControls.FaultException(string.Format("Could not find report '{0}'.", url));
            } catch (Exception) {
                throw new DevExpress.XtraReports.Web.ClientControls.FaultException(string.Format("Could not find report '{0}'.", url));
            }
        }

        public override Dictionary<string, string> GetUrls() {
            // Returns a dictionary of the existing report URLs and display names. 
            // This method is called when running the Report Designer, 
            // before the Open Report and Save Report dialogs are shown and after a new report is saved.

            return Directory.GetFiles(ReportDirectory, "*" + FileExtension)
                                     .Select(Path.GetFileNameWithoutExtension)
                                     .ToDictionary<string, string>(x => x);
        }

        public override void SetData(XtraReport report, string url) {
            // Stores the specified report to a Report Storage using the specified URL. 
            // This method is called only after the IsValidUrl and CanSetData methods are called.
            report.SaveLayoutToXml(Path.Combine(ReportDirectory, url + FileExtension));
        }

        public override string SetNewData(XtraReport report, string defaultUrl) {
            // Stores the specified report using a new URL. 
            // The IsValidUrl and CanSetData methods are never called before this method. 
            // You can validate and correct the specified URL directly in the SetNewData method implementation 
            // and return the resulting URL used to save a report in your storage.
            SetData(report, defaultUrl);
            return defaultUrl;
        }
    }
}