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());
}
//...
}