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

ReportStorageWebExtension Class

A report storage for Web Reporting.

Namespace: DevExpress.XtraReports.Web.Extensions

Assembly: DevExpress.XtraReports.v21.2.Web.dll

NuGet Package: DevExpress.Web.Reporting.Common

Declaration

public abstract class ReportStorageWebExtension :
    IReportStorageTool,
    IReportStorageWebTool,
    IReportStorageTool2

Remarks

When you bind the Web Document Viewer or Report Designer to a report specified by name (a string identifier), the control uses custom services, registered in the application, to resolve a report name to a report object. The services are queried in the following order:

  1. IWebDocumentViewerReportResolver (Web Document Viewer only)
  2. IReportProvider
  3. ReportStorageWebExtension

When you save a report in the Web Report Designer, the ReportStorageWebExtension service is called to save the report data.

Create the ReportStorageWebExtension class descendant and register it in your application to implement a custom report storage.

Refer to the following help topics for more information:

Examples

For a code example, create a new Web project from the DevExpress Visual Studio template and review the code for the CustomReportStorageWebExtension class in the Services folder.

  • Report Storage based on a file system:

    Show code
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.ServiceModel;
    using DevExpress.XtraReports.Web.Extensions;
    using DevExpress.XtraReports.UI;
    using MvcSample.PredefinedReports;
    
    namespace MvcSample.Services
    {
        public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
        {
            readonly string reportDirectory;
            const string FileExtension = ".repx";
            public CustomReportStorageWebExtension(string reportDirectory) {
                if (!Directory.Exists(reportDirectory)) {
                    Directory.CreateDirectory(reportDirectory);
                }
                this.reportDirectory = reportDirectory;
            }
    
            private bool IsWithinReportsFolder(string url, string folder) {
                var rootDirectory = new DirectoryInfo(folder);
                var fileInfo = new FileInfo(Path.Combine(folder, url));
                return fileInfo.Directory.FullName.ToLower().StartsWith(rootDirectory.FullName.ToLower());
            }
    
            public override bool CanSetData(string url) {
                // Determines whether a report with the specified URL can be saved.
                // Add custom logic that returns **false** for reports that should be read-only.
                // Return **true** if no valdation is required.
                // This method is called only for valid URLs (if the **IsValidUrl** method returns **true**).
    
                return true;
            }
    
            public override bool IsValidUrl(string url) {
                // 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.
                // Return **true** if no validation is required.
    
                return Path.GetFileName(url) == url;
            }
    
            public override byte[] GetData(string url) {
                // Uses a specified URL to return report layout data stored within a report storage medium.
                // This method is called if the **IsValidUrl** method returns **true**.
                // 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.
                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();
                        }
                    }
                } catch (Exception) {
                    throw new FaultException(new FaultReason("Could not get report data."), 
                        new FaultCode("Server"), "GetData");
                }
                throw new FaultException(new FaultReason(string.Format("Could not find report '{0}'.", url)), 
                    new FaultCode("Server"), "GetData");
            }
    
            public override Dictionary<string, string> GetUrls() {
                // Returns a dictionary that contains the report names (URLs) and display names. 
                // The Report Designer uses this method to populate the Open Report and Save Report dialogs.
    
                return Directory.GetFiles(reportDirectory, "*" + FileExtension)
                                         .Select(Path.GetFileNameWithoutExtension)
                                         .Union(ReportsFactory.Reports.Select(x => x.Key))
                                         .ToDictionary<string, string>(x => x);
            }
    
            public override void SetData(XtraReport report, string url) {
                // Saves the specified report to the report storage with the specified name
                // (saves existing reports only).
    
                if(!IsWithinReportsFolder(url, reportDirectory))
                    throw new FaultException(new FaultReason("Invalid report name."), new FaultCode("Server"), "GetData");
                report.SaveLayoutToXml(Path.Combine(reportDirectory, url + FileExtension));
            }
    
            public override string SetNewData(XtraReport report, string defaultUrl) {
                // Allows you to validate and correct the specified name (URL).
                // This method also allows you to return the resulting name (URL),
                // and to save your report to a storage. The method is called only for new reports.
    
                SetData(report, defaultUrl);
                return defaultUrl;
            }
        }
    }
    
  • Report Storage based on a SQLite database:

    Show code
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using DevExpress.XtraReports.UI;
    using AspNetCoreSample.PredefinedReports;
    using AspNetCoreSample.Data;
    
    namespace AspNetCoreSample.Services
    {
        public class CustomReportStorageWebExtension : 
            DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
        {
            protected ReportDbContext DbContext { get; set; }
            public CustomReportStorageWebExtension(ReportDbContext dbContext) {
                this.DbContext = dbContext;
            }
    
            public override bool CanSetData(string url) {
                // Determines whether a report with the specified URL can be saved.
                // Add custom logic that returns **false** for reports that should be read-only.
                // Return **true** if no valdation is required.
                // This method is called only for valid URLs (if the **IsValidUrl** method returns **true**).
    
                return true;
            }
    
            public override bool IsValidUrl(string url) {
                // 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.
                // Return **true** if no validation is required.
    
                return true;
            }
    
            public override byte[] GetData(string url) {
                // Uses a specified URL to return report layout data stored within a report storage medium.
                // This method is called if the **IsValidUrl** method returns **true**.
                // 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.
                var reportData = DbContext.Reports.FirstOrDefault(x => x.Name == url);
                if(reportData != null)
                    return reportData.LayoutData;
    
                if(ReportsFactory.Reports.ContainsKey(url)) {
                    using var ms = new MemoryStream();
                    using XtraReport report = ReportsFactory.Reports[url]();
                    report.SaveLayoutToXml(ms);
                    return ms.ToArray();
                }
                throw new DevExpress.XtraReports.Web.ClientControls.FaultException(
                    string.Format("Could not find report '{0}'.", url));
            }
    
            public override Dictionary<string, string> GetUrls() {
                // Returns a dictionary that contains the report names (URLs) and display names. 
                // The Report Designer uses this method to populate the Open Report and Save Report dialogs.
    
                return DbContext.Reports
                    .ToList()
                    .Select(x => x.Name)
                    .Union(ReportsFactory.Reports.Select(x => x.Key))
                    .ToDictionary<string, string>(x => x);
            }
    
            public override void SetData(XtraReport report, string url) {
                // Saves the specified report to the report storage with the specified name
                // (saves existing reports only). 
                using var stream = new MemoryStream(); report.SaveLayoutToXml(stream);
                var reportData = DbContext.Reports.FirstOrDefault(x => x.Name == url);
                if(reportData == null) {
                    DbContext.Reports.Add(new ReportItem { Name = url, LayoutData = stream.ToArray() });
                } else {
                    reportData.LayoutData = stream.ToArray();
                }
                DbContext.SaveChanges();
            }
    
            public override string SetNewData(XtraReport report, string defaultUrl) {
                // Allows you to validate and correct the specified name (URL).
                // This method also allows you to return the resulting name (URL),
                // and to save your report to a storage. The method is called only for new reports.
                SetData(report, defaultUrl);
                return defaultUrl;
            }
        }
    }
    

Inheritance

Object
ReportStorageWebExtension
See Also