This example incorporates the Web Report Designer into a client-side app built with React. The example consists of two parts:
- The ServerSideApp folder contains the backend project. The project is an ASP.NET Core application that enables cross-domain requests (CORS) (Access-Control-Allow-Origin) and implements custom web report storage.
- The react-report-designer folder contains the client application built with React.
This project contains code snippets used for client-side customization and reflected in our online help topics. Each code snippet is enclosed in a page.tsx
file in a separate folder. After running the project, navigate the following locations to see the result:
Location | Description |
---|---|
/client-side-api | Performs some client-side actions. |
/save-modified-report | Saves a modified report in the currently active tab. Saves all modified reports. |
/manage-properties-panel | Hides or disables individual editors or sections in the Properties panel for the specified control type. |
/report-designer-api | Calls the Report Designer's RunWizard method to invoke New Report Wizard. |
/open-report | Adds a button that loads a specified report. |
/save-report | Adds a button that saves the current report. |
Quick Start
Server
In the ServerSideApp/ServerSideApp folder, run the following command:
Codedotnet run
The server starts at http://localhost:5000. To debug the server, run the application in Visual Studio.
Client
In the react-report-designer folder, run the following commands:
Codenpm install
npm run dev
Open http://localhost:3000/
in your browser to view the result. The application displays the Web Report Designer.
Files to Review
Documentation
- Create a React Application with Web Report Designer
- Report Designer Server-Side Configuration (ASP.NET Core)
More Examples
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
Code'use client';
import dynamic from 'next/dynamic'
import RequestOptions from 'devexpress-reporting-react/dx-report-designer/options/RequestOptions';
const ReportDesigner = dynamic(() => import('devexpress-reporting-react/dx-report-designer'), {ssr: false})
function App() {
return (
<ReportDesigner reportUrl="TestReport">
<RequestOptions host="http://localhost:5000/" getDesignerModelAction="DXXRD/GetDesignerModel" />
</ReportDesigner>
)
}
export default App
C#using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using DevExpress.AspNetCore;
using DevExpress.AspNetCore.Reporting;
using DevExpress.Security.Resources;
using DevExpress.XtraReports.Web.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ServerSideApp.Services;
using ServerSideApp.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDevExpressControls();
builder.Services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>();
builder.Services.AddMvc();
builder.Services.ConfigureReportingServices(configurator => {
if(builder.Environment.IsDevelopment()) {
configurator.UseDevelopmentMode();
}
configurator.ConfigureReportDesigner(designerConfigurator => {
});
configurator.ConfigureWebDocumentViewer(viewerConfigurator => {
viewerConfigurator.UseCachedReportSourceBuilder();
viewerConfigurator.RegisterConnectionProviderFactory<CustomSqlDataConnectionProviderFactory>();
});
});
builder.Services.AddDbContext<ReportDbContext>(options => options.UseSqlite(builder.Configuration.GetConnectionString("ReportsDataConnectionString")));
builder.Services.AddCors(options => {
options.AddPolicy("AllowCorsPolicy", builder => {
// Allow all ports on local host.
builder.SetIsOriginAllowed(origin => new Uri(origin).Host == "localhost");
builder.AllowAnyHeader();
builder.AllowAnyMethod();
});
});
var app = builder.Build();
using(var scope = app.Services.CreateScope()) {
var services = scope.ServiceProvider;
services.GetService<ReportDbContext>().InitializeDatabase();
}
var contentDirectoryAllowRule = DirectoryAccessRule.Allow(new DirectoryInfo(Path.Combine(builder.Environment.ContentRootPath, "Content")).FullName);
AccessSettings.ReportingSpecificResources.TrySetRules(contentDirectoryAllowRule, UrlAccessRule.Allow());
DevExpress.XtraReports.Configuration.Settings.Default.UserDesignerOptions.DataBindingMode = DevExpress.XtraReports.UI.DataBindingMode.Expressions;
app.UseDevExpressControls();
System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
if(app.Environment.IsDevelopment()) {
app.UseDeveloperExceptionPage();
} else {
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors("AllowCorsPolicy");
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
C#using System.Collections.Generic;
using System.Threading.Tasks;
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;
using DevExpress.DataAccess.Sql;
using DevExpress.XtraReports.Web.ReportDesigner.Services;
using Microsoft.AspNetCore.Mvc;
namespace ServerSideApp.Controllers {
public class CustomReportDesignerController : ReportDesignerController {
public CustomReportDesignerController(IReportDesignerMvcControllerService controllerService) : base(controllerService) {
}
[HttpPost("[action]")]
public async Task<IActionResult> GetDesignerModel(
[FromForm] string reportName,
[FromServices] IReportDesignerModelBuilder reportDesignerModelBuilder) {
var dataSources = new Dictionary<string, object>();
var 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();
dataSources.Add("Northwind", ds);
reportName = string.IsNullOrEmpty(reportName) ? "TestReport" : reportName;
var designerModel = await reportDesignerModelBuilder
.Report(reportName)
.DataSources(dataSources)
.BuildModelAsync();
return DesignerModel(designerModel);
}
}
public class CustomQueryBuilderController : QueryBuilderController {
public CustomQueryBuilderController(IQueryBuilderMvcControllerService controllerService) : base(controllerService) {
}
}
public class CustomWebDocumentViewerController : WebDocumentViewerController {
public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService) : base(controllerService) {
}
}
}