Skip to main content
All docs
V24.2

IReportProviderAsync Interface

Allows you to implement a service that asynchronously resolves a report name to a report instance.

Namespace: DevExpress.XtraReports.Services

Assembly: DevExpress.XtraReports.v24.2.dll

NuGet Package: DevExpress.Reporting.Core

Declaration

public interface IReportProviderAsync

Remarks

You can create a custom service that implements the IReportProviderAsync interface to resolve a string to a report instance.

The GetModelAsync methods call this service to get a report by its unique name (also referred to as the report URL). When a report contains subreports with the names specified by the XRSubreport.ReportSourceUrl property, the IReportProvider service is used to resolve subreport names.

A custom IReportProviderAsync service has priority over the custom ReportStorageWebExtension service.

In your project, you must bind report controls to the WebDocumentViewerModel or ReportDesignerModel objects originated from controllers. The controller-based models allow you to use asynchronous API and avoid obscure errors that may occur when a subreport fails to load and throws an exception, or when an attempt to refresh a list of predefined dynamic parameter values fails.

A controller must call the WebDocumentViewerClientSideModelGenerator.GetModelAsync or ReportDesignerClientSideModelGenerator.GetModelAsync methods to generate report models and send them to the Document Viewer and End User Report Designer.

Implementation

Add custom logic to the GetReportAsync method. The method instantiates and returns a report based on the specified report unique name. The following code is the IReportProviderAsync implementation that retrieves a serialized report from the report storage:

using System.IO;
using System.Threading.Tasks;
using DevExpress.XtraReports.Services;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.Extensions;

// ...
    public class CustomReportProviderAsync : IReportProviderAsync
    {
        readonly ReportStorageWebExtension reportStorageWebExtension;

        public CustomReportProviderAsync(ReportStorageWebExtension reportStorageWebExtension)
        {
            this.reportStorageWebExtension = reportStorageWebExtension;
        }
        public async Task<XtraReport> GetReportAsync(string id, ReportProviderContext context)
        {
            var reportLayout = await reportStorageWebExtension.GetDataAsync(id);
            if (reportLayout == null)
                return null;
            using (var ms = new MemoryStream(reportLayout))
            {
                var report = XtraReport.FromXmlStream(ms);
                return report;
            }
        }
    }

Registration

ASP.NET Web Forms and ASP.NET MVC

Call the following methods at application startup:

using DevExpress.XtraReports.Services;
// ...
void Application_Start() {
    // ...
    DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.Register<IReportProviderAsync, CustomReportProviderAsync>();
    DevExpress.XtraReports.Web.WebDocumentViewer.DefaultWebDocumentViewerContainer.Register<IReportProviderAsync, CustomReportProviderAsync>();
    //...
    DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.UseAsyncEngine();
    DevExpress.XtraReports.Web.WebDocumentViewer.DefaultWebDocumentViewerContainer.UseAsyncEngine();
}
ASP.NET Core

Call the AddScoped method at application startup to register the service and use the ReportingConfigurationBuilder.UseAsyncEngine method to enable asynchronous mode:

using Microsoft.Extensions.DependencyInjection;
using DevExpress.XtraReports.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<IReportProviderAsync, CustomReportProviderAsync>();

builder.Services.ConfigureReportingServices(configurator => {
    configurator.UseAsyncEngine();
});

var app = builder.Build();

Usage Example

The complete sample project is available on GitHub:

View Example: How to Use the Asynchronous Engine for Web Reporting

The following code is a controller action method that handles incoming browser requests. It uses a custom IReportProviderAsync service to obtain a subreport when a report is exported to PDF.

using System.Collections.Generic;
using System.ComponentModel.Design;
using System.IO;
using System.Threading.Tasks;
using DevExpress.AspNetCore.Reporting.WebDocumentViewer;
using DevExpress.DataAccess.Sql;
using DevExpress.XtraReports.Services;
using DevExpress.XtraReports.Web.ReportDesigner.Services;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using Microsoft.AspNetCore.Mvc;

// ...
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        public async Task<IActionResult> Designer([FromServices] IReportDesignerModelBuilder reportDesignerModelBuilder, [FromQuery] string reportName = "RootReport")
        {
            var dataSources = new Dictionary<string, object>
            {
                ["Northwind"] = GetNorthwindSqlDataSource()
            };
            var designerModel = await reportDesignerModelBuilder
                .DataSources(dataSources)
                .Report(reportName)
                .BuildModelAsync();
            return View(designerModel);
        }

        public async Task<IActionResult> Viewer([FromServices] IWebDocumentViewerClientSideModelGenerator modelGenerator, [FromQuery] string reportName = "RootReport")
        {
            var viewerModel = await modelGenerator.GetModelAsync(reportName, WebDocumentViewerController.DefaultUri);
            return View(viewerModel);
        }
        public async Task<IActionResult> ExportToPdf([FromServices] IReportProviderAsync reportProviderAsync, [FromQuery] string reportName = "RootReport")
        {
            var report = await reportProviderAsync.GetReportAsync(reportName, null);
            var reportServiceContainer = (IServiceContainer)report;
            reportServiceContainer.RemoveService(typeof(IReportProviderAsync));
            reportServiceContainer.AddService(typeof(IReportProviderAsync), reportProviderAsync);
            using (var stream = new MemoryStream()) {
                await report.CreateDocumentAsync();
                await report.ExportToPdfAsync(stream);
                return File(stream.ToArray(), System.Net.Mime.MediaTypeNames.Application.Pdf);
            }
        }

        SqlDataSource GetNorthwindSqlDataSource()
        {
            // Create a SQL data source with the specified connection string.
            SqlDataSource ds = new SqlDataSource("NWindConnectionString");
            // Create a SQL query to access the Products data table.
            SelectQuery query = SelectQueryFluentBuilder.AddTable("Products").SelectAllColumnsFromTable().Build("Products");
            ds.Queries.Add(query);
            ds.RebuildResultSchema();
            return ds;
        }
    }

Note

Review the Open a Report in ASP.NET Core Application help topic for more information.

See Also