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 (database, file system, cloud, etc.) to save and load reports. You should explicitly implement a report storage class to store reports with specific identifiers (URLs) and register this storage in your application.

How to Implement a Custom Report Storage

Add a new class, inherit it from the abstract ReportStorageWebExtension class and implement the following methods:

  • IsValidUrl - Determines whether the URL passed to the current report storage is valid. Implement your own logic to prohibit URLs that contain spaces or other specific characters. This method is called before the CanSetData and GetData methods.

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

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

  • SetNewData - Saves the specified report with a new URL (i.e., it saves new reports only). The IsValidUrl and CanSetData methods are not called before this method. You can validate and correct the specified URL in the SetNewData method implementation and return the resulting URL.

  • GetData - Returns a report layout with the specified URL from the report storage. This method is called if the IsValidUrl method returns true.

    TIP

    You can use the GetData method to process report parameters sent from the client if the parameters are included in the report URL's query string.

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

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 the report storage that stores reports in a file system. This code is used in the DevExpress Template Gallery.

IMPORTANT

The template generates a sample storage (a ReportStorageWebExtension descendant) for demonstration purposes only. It should not be used in production code.

Show content
using DevExpress.XtraReports.UI;
using DXWebApplication9.PredefinedReports;
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));
                }
                if (ReportsFactory.Reports.ContainsKey(url))
                {
                    using (MemoryStream ms = new MemoryStream()) {
                        ReportsFactory.Reports[url]().SaveLayoutToXml(ms);
                        return ms.ToArray();
                    }
                }
                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 to a storage.

            return Directory.GetFiles(ReportDirectory, "*" + FileExtension)
                                     .Select(Path.GetFileNameWithoutExtension)
                                     .Concat(ReportsFactory.Reports.Select(x => x.Key))
                                     .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;
        }
    }
}