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

Implement a Report Storage

  • 5 minutes to read

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 using specific identifiers (URLs) and register this storage in your application.

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

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

  • ReportStorageWebExtension.CanSetData - Determines whether a report with the specified URL can be saved. 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 (if the IsValidUrl method returns true) before the SetData method is called.

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

  • ReportStorageWebExtension.SetNewData - Saves the specified report with a new URL (that is, saves new reports only). 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 to save the report.

  • ReportStorageWebExtension.GetData - Returns a report layout with the specified URL from the report storage. This method is called only for valid URLs after the IsValidUrl method is called.

  • ReportStorageWebExtension.GetUrls - Returns a dictionary of existing report URLs and display names. This method is called when the Report Designer runs, before the Open Report and Save Report dialogs are shown, and after a new report is saved to the storage.

For example, you can use the following implementation to store reports in a database:

Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.IO
Imports System.Linq
Imports DevExpress.XtraReports.UI
Imports SimpleWebReportCatalog.CatalogDataTableAdapters
' ...

Namespace SimpleWebReportCatalog
    Public Class CustomReportStorageWebExtension
        Inherits DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension

        Private catalogDataSet As CatalogData
        Private reportsTable As DataTable
        Private reportsTableAdapter As ReportsTableAdapter


        Public Sub New()
            catalogDataSet = New CatalogData()
            reportsTableAdapter = New ReportsTableAdapter()
            reportsTableAdapter.Fill(catalogDataSet.Reports)
            reportsTable = catalogDataSet.Tables("Reports")
        End Sub


        Public Overrides Function CanSetData(ByVal url As String) As Boolean
            ' Check if the URL is available in the report storage.
            Return reportsTable.Rows.Find(Integer.Parse(url)) IsNot Nothing
        End Function


        Public Overrides Function GetData(ByVal url As String) As Byte()
            ' Get the report data from the storage.
            Dim row As DataRow = reportsTable.Rows.Find(Integer.Parse(url))
            If row Is Nothing Then
                Return Nothing
            End If

            Dim reportData() As Byte = DirectCast(row("LayoutData"), Byte())
            Return reportData
        End Function


        Public Overrides Function GetUrls() As Dictionary(Of String, String)
          ' Get URLs and display names for all reports available in the storage.
          Return reportsTable.AsEnumerable().ToDictionary(Function(dataRow) CInt((dataRow("ReportID"))).ToString(), Function(dataRow) CStr(dataRow("DisplayName")))
        End Function


        Public Overrides Function IsValidUrl(ByVal url As String) As Boolean
            ' Check if the specified URL is valid for the current report storage.
            ' In this example, a URL should be a string containing a numeric value that is used as a data row primary key.
            Dim n As Integer = Nothing
            Return Integer.TryParse(url, n)
        End Function


        Public Overrides Sub SetData(ByVal report As XtraReport, ByVal url As String)
            ' Write a report to the storage under the specified URL.
            Dim row As DataRow = reportsTable.Rows.Find(Integer.Parse(url))

            If row IsNot Nothing Then
                Using ms As New MemoryStream()
                    report.SaveLayoutToXml(ms)
                    row("LayoutData") = ms.GetBuffer()
                End Using
                reportsTableAdapter.Update(catalogDataSet)
                catalogDataSet.AcceptChanges()
            End If
        End Sub


        Public Overrides Function SetNewData(ByVal report As XtraReport, ByVal defaultUrl As String) As String
            ' Save a report to the storage under a new URL. 
            ' The defaultUrl parameter contains the report display name specified by a user.
            Dim row As DataRow = reportsTable.NewRow()

            row("DisplayName") = defaultUrl
            Using ms As New MemoryStream()
                report.SaveLayoutToXml(ms)
                row("LayoutData") = ms.GetBuffer()
            End Using

            reportsTable.Rows.Add(row)
            reportsTableAdapter.Update(catalogDataSet)
            catalogDataSet.AcceptChanges()

            ' Refill the dataset to obtain the actual value of the new row's autoincrement key field.
            reportsTableAdapter.Fill(catalogDataSet.Reports)
            Return catalogDataSet.Reports.FirstOrDefault(Function(x) x.DisplayName = defaultUrl).ReportID.ToString()
        End Function
    End Class
End Namespace

Use the static ReportStorageWebExtension.RegisterExtensionGlobal method at the application’s startup to register the implemented report storage.

using DevExpress.AspNetCore;
using DevExpress.AspNetCore.Reporting;
//... 

public class Startup {
//... 
    public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
        // ...
        DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension.RegisterExtensionGlobal(new CustomReportStorageWebExtension());   
    }
//...    
}