Skip to main content

Integrate Blazor Server Reporting (JavaScript-Based) Controls in DevExpress Blazor Application

  • 8 minutes to read

Tip

To create a Blazor Reporting application, use preconfigured DevExpress templates that allow you to create an application with minimal effort and maximum efficiency. For more information, review the following help topics:

This tutorial describes how to integrate the Document Viewer and Report Designer controls in a sample Blazor Server application created from the DevExpress Blazor template.

View Example

Tip

You can start with the DevExpress Blazor reporting template to create a sample application with already integrated Reporting controls, as described in the following help topic: Get Started with Blazor Reporting.

Prerequisites

  1. Install the .NET 6.0 or later SDK.
  2. Install Visual Studio 2022 (latest version) with the ASP.NET and web development workload.
  3. Use the DevExpress .NET Product Installer to install DevExpress Blazor components.

When you use the DevExpress .NET Product Installer to install Blazor components, the DevExpress Template Gallery automatically appears in Visual Studio’s New Project menu. The Gallery contains DevExpress Blazor project templates.

Create a New Blazor Application

Perform the following steps to create a sample Blazor application in Visual Studio:

  1. Click Create a new project on Visual Studio’s start page and select the DevExpress v23.2 Blazor App Template Gallery.

    Create a new project

    Click Next.

  2. Specify the project name and location.

    Blazor Configure New Project

    Click Create.

  3. Select the Blazor Server Application.

    Blazor Select Server Application

    Click Run Wizard.

  4. The DevExpress Blazor Project Wizard allows you to select a theme to change the appearance of all components, and specify the culture used to localize UI elements. Click Create Project.

    DevExpress Blazor Wizard

The Server Application template creates a project that includes the following:

Install the DevExpress Blazor Reporting NuGet Package

  1. Right-click the Dependencies node in the Solution Explorer and select Manage NuGet Packages….

  2. In the invoked dialog, click the Browse tab, select the DevExpress 23.2 Local package source, and install the DevExpress.Blazor.Reporting.JSBasedControls NuGet package.

  3. Select the DevExpress 23.2 Local package source, and install the DevExpress.AspNetCore.Reporting NuGet package.

    The DevExpress 23.2 Local package is automatically added as a package source to your NuGet configuration files if you use the DevExpress .NET Product Installer.

    Blazor Install NuGet Package JSBased Server

    Note

    The following NuGet packages are available from the local NuGet feed if you have DevExpress products installed locally, and in the DevExpress NuGet Gallery at https://nuget.devexpress.com/:

    DevExpress.Blazor.Reporting.Viewer
    Contains the Report Viewer native component for Blazor.
    DevExpress.Blazor.Reporting.JSBasedControls
    Contains the Document Viewer and Report Designer JavaScript-based components for Blazor Server and standalone Blazor WebAssembly apps.
    DevExpress.Blazor.Reporting.JSBasedControls.WebAssembly
    Contains the Document Viewer and Report Designer JavaScript-based components for hosted Blazor WebAssembly apps.
    DevExpress.Blazor.Reporting.JSBasedControls.Common
    Contains common settings and client-side resources for the JavaScript-based Blazor Reporting components.
  4. Build the project.

Add Dependencies

  1. Modify the Program.cs file as follows:

    using DevExpress.Blazor.Reporting;
    using DevExpress.XtraReports.Web.Extensions;
    // ...
    builder.Services.AddDevExpressBlazorReporting();
    // ...
    app.UseDevExpressBlazorReporting();
    
  2. Modify the _Imports.razor file to register the DevExpress.Blazor.Reporting namespace:

    @using DevExpress.Blazor.Reporting  
    

Add the Report Storage

  1. Implement the ReportStorageWebExtension descendant that saves and loads reports. The code below is a sample storage that uses the file system to store reports. Add the CustomReportStorageWebExtension.cs class file to your project with the following contents:

    using DevExpress.XtraReports.UI;
    using System.ServiceModel;
    
    public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
    {
        readonly string reportDirectory = "Reports";
        const string FileExtension = ".repx";
        public CustomReportStorageWebExtension()
        {
            if (!Directory.Exists(reportDirectory))
            {
                Directory.CreateDirectory(reportDirectory);
            }
        }
    
        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));
                }
            }
            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)
                                    .ToDictionary(x => Path.GetFileNameWithoutExtension(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). 
            var resolvedUrl = Path.GetFullPath(Path.Combine(reportDirectory, url + FileExtension));
            if (!resolvedUrl.StartsWith(reportDirectory + Path.DirectorySeparatorChar)) {
                throw new FaultException("Invalid report name.");
            }
    
            report.SaveLayoutToXml(resolvedUrl);
        }
    
        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;
        }
    }
    

    The HelloWorld class instance in the ReportFactory.Reports method is a sample XtraReport class created as described in the next section.

  2. Modify the Program.cs file and add the code that registers the CustomReportStorageWebExtension:

    using DevExpress.XtraReports.Web.Extensions;
    // ...
    builder.Services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>();
    

    Important

    Register the ReportStorageWebExtension after the AddDevExpressBlazorReporting method.

  3. Add a new Reports folder to a project.

    Tip

    The name Reports is specified in the ReportStorageWebExtension implementation.

Create a Sample Report

Note

To perform this step, you should install DevExpress Reporting on your machine. Refer to the following topic for more information: Run the Wizard Dialog - DevExpress Unified Component Installer.

  1. Select Project -> Add New Item… to invoke the Add New Item dialog. Navigate to the Reporting node and select the DevExpress v.23.2 Report item template.

    Add a New Report

    Name the report TestReport.cs and click Add.

  2. Select Blank in the invoked Report Wizard page and click Finish.

    Report Wizard New Blank Report

  3. Modify the newly created report in the Visual Studio Report Designer. Add a label and type Hello, World!:

    Edit a Report in the VS Designer

  4. Click the report’s smart tag and select Save…:

    Save New Report

    In the invoked Save As dialog, specify the Reports project folder, Report XML Files (.repx) file type, and the TestReport.repx file name.

Create Routing to Controller Actions

Modify the Program.cs file. Add the following code to map requests to controller actions:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

Implement Default Controllers

  1. In Visual Studio, create a new Controllers folder.
  2. Add a new class file (ReportingControllers.cs) with the following content:

    using DevExpress.AspNetCore.Reporting.QueryBuilder;
    using DevExpress.AspNetCore.Reporting.QueryBuilder.Native.Services;
    using DevExpress.AspNetCore.Reporting.ReportDesigner;
    using DevExpress.AspNetCore.Reporting.ReportDesigner.Native.Services;
    using DevExpress.AspNetCore.Reporting.WebDocumentViewer;
    using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services;
    
        public class CustomWebDocumentViewerController : WebDocumentViewerController {
            public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService) : base(controllerService) {
            }
        }
    
        public class CustomReportDesignerController : ReportDesignerController {
            public CustomReportDesignerController(IReportDesignerMvcControllerService controllerService) : base(controllerService) {
            }
        }
    
        public class CustomQueryBuilderController : QueryBuilderController {
            public CustomQueryBuilderController(IQueryBuilderMvcControllerService controllerService) : base(controllerService) {
            }
        }
    

Add Document Viewer to a Page

Create a new Razor component (select Project -> Add New Item… -> Razor Component). Save it as the DocumentViewer.razor file, and open and overwrite its content with the following:

@page "/documentviewer"

<DxDocumentViewer ReportName="TestReport" Height="1000px" Width="100%">
    <DxDocumentViewerTabPanelSettings Width="340" />
</DxDocumentViewer>

The DxDocumentViewer component invokes the default WebDocumentViewerController that processes requests from the Document Viewer and loads the TestReport report to create a document.

Add Report Designer to a Page

Create a new Razor component (select Project -> Add New Item… -> Razor Component). Save it as the ReportDesigner.razor file, and open and overwrite its content with the following:

@page "/reportdesigner"

<DxReportDesigner ReportName="TestReport" Height="1000px" Width="100%" AllowMDI="true">
    <DxReportDesignerWizardSettings UseFullscreenWizard="true" />
</DxReportDesigner>

The DxReportDesigner loads the TestReport report.

Note

If you implement a custom report that inherits from XtraReport and want to open it in the End-User Report Designer, add a constructor without parameters to this report.

Modify the NavMenu.razor file to include links to the newly created pages:

<Items>
    <DxMenuItem NavigateUrl="/" Text="Home" CssClass="menu-item" IconCssClass="icon home-icon"></DxMenuItem>
    <DxMenuItem NavigateUrl="/counter" Text="Counter" CssClass="menu-item" IconCssClass="icon counter-icon"></DxMenuItem>
    <DxMenuItem NavigateUrl="/weather" Text="Weather" CssClass="menu-item" IconCssClass="icon weather-icon"></DxMenuItem>
    <DxMenuItem NavigateUrl="/documentviewer" Text="Document Viewer" CssClass="menu-item"> </DxMenuItem>
    <DxMenuItem NavigateUrl="/reportdesigner" Text="Report Designer" CssClass="menu-item"> </DxMenuItem>
</Items>

Run the Project

Run the project. The Document Viewer and Report Designer components load the TestReport.repx report: