This example shows how to add a custom Export to PDF button that exports all dashboard items into the same PDF document.
Client
On the client, the ViewerApiExtensionOptions.onDashboardTitleToolbarUpdated event is handled to modify the dashboard title and add the custom export button to it. This functionality is encapsulated into a custom dashboard extension (the ExportAllItemsExtension.js file).
To perform the export operation, the client sends a GET request to a custom Export Controller.
Server
The custom Export Controller processes requests from the client side. This controller uses the following classes:
- The WebDashboardExporter class exports dashboard items to PDF.
- The PdfDocumentProcessor class joins exported documents together.
Files to Review
- ExportAllItemsExtension.js
- Startup.cs
- CustomDashboardStorage.cs
- ExportController.cs
- DashboardExportModel.cs
- _Layout.cshtml
- Index.cshtml
Documentation
More Examples
- Dashboard for ASP.NET Core - How to load and save dashboards from/to a database
- Dashboard for MVC - How to implement server-side export
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
JavaScriptvar ExportAllItemsExtension = (function () {
var _dashboardControl;
var _exportRoute;
// Viewer
function customizeTitleToolbar(e) {
e.options.actionItems.push({
icon: 'dx-dashboard-export-to-pdf',
tooltip: 'Export All Items',
type: 'button',
click: performExport
});
}
function performExport(e) {
var queryParameters = new URLSearchParams({
dashboardId: _dashboardControl.getDashboardId(),
state: _dashboardControl.getDashboardState()
});
window.open(`${_exportRoute}?${queryParameters}`);
}
// Event Subscription
function ExportAllItemsExtension(dashboardControl, exportRoute) {
this.name = "exportAllItems";
_dashboardControl = dashboardControl;
_exportRoute = exportRoute;
this.start = function () {
var viewerApiExtension = _dashboardControl.findExtension('viewerApi');
if (viewerApiExtension) {
viewerApiExtension.on('dashboardTitleToolbarUpdated', customizeTitleToolbar);
}
};
this.stop = function () {
var viewerApiExtension = _dashboardControl.findExtension('viewerApi');
if (viewerApiExtension) {
viewerApiExtension.off('itemCaptionToolbarUpdated', customizeTitleToolbar);
}
};
}
return ExportAllItemsExtension;
}());
C#using AspNetCoreDashboard_ExportAllItems.Classes;
using DevExpress.AspNetCore;
using DevExpress.DashboardAspNetCore;
using DevExpress.DashboardCommon;
using DevExpress.DashboardWeb;
using DevExpress.DataAccess.Excel;
using DevExpress.DataAccess.Sql;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using System;
namespace AspNetCoreDashboard_ExportAllItems {
public class Startup {
public Startup(IConfiguration configuration, IWebHostEnvironment hostingEnvironment) {
Configuration = configuration;
FileProvider = hostingEnvironment.ContentRootFileProvider;
DashboardExportSettings.CompatibilityMode = DashboardExportCompatibilityMode.Restricted;
}
public IFileProvider FileProvider { get; }
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
services
.AddResponseCompression()
.AddDevExpressControls()
.AddMvc();
services.AddScoped<DashboardConfigurator>((IServiceProvider serviceProvider) => {
DashboardConfigurator configurator = new DashboardConfigurator();
CustomDashboardStorage customDashboardStorage = new CustomDashboardStorage(FileProvider.GetFileInfo("Data/Dashboards").PhysicalPath);
configurator.SetDashboardStorage(customDashboardStorage);
DataSourceInMemoryStorage dataSourceStorage = new DataSourceInMemoryStorage();
// Registers an SQL data source.
DashboardSqlDataSource sqlDataSource = new DashboardSqlDataSource("SQL Data Source", "NWindConnectionString");
sqlDataSource.DataProcessingMode = DataProcessingMode.Client;
SelectQuery query = SelectQueryFluentBuilder
.AddTable("Categories")
.Join("Products", "CategoryID")
.SelectAllColumns()
.Build("Products_Categories");
sqlDataSource.Queries.Add(query);
dataSourceStorage.RegisterDataSource("sqlDataSource", sqlDataSource.SaveToXml());
// Registers an Object data source.
DashboardObjectDataSource objDataSource = new DashboardObjectDataSource("Object Data Source");
dataSourceStorage.RegisterDataSource("objDataSource", objDataSource.SaveToXml());
// Registers an Excel data source.
DashboardExcelDataSource excelDataSource = new DashboardExcelDataSource("Excel Data Source");
excelDataSource.FileName = FileProvider.GetFileInfo("Data/Sales.xlsx").PhysicalPath;
excelDataSource.SourceOptions = new ExcelSourceOptions(new ExcelWorksheetSettings("Sheet1"));
dataSourceStorage.RegisterDataSource("excelDataSource", excelDataSource.SaveToXml());
configurator.SetDataSourceStorage(dataSourceStorage);
configurator.DataLoading += (s, e) => {
if(e.DataSourceName == "Object Data Source") {
e.Data = Invoices.CreateData();
}
};
return configurator;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
if(env.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.UseDevExpressControls();
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapDashboardRoute("dashboardControl", "DefaultDashboard");
endpoints.MapRazorPages();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
C#using DevExpress.DashboardWeb;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace AspNetCoreDashboard_ExportAllItems.Classes {
public class CustomDashboardStorage : DashboardFileStorage {
public CustomDashboardStorage(string path) : base(path) { }
public XDocument GetDashboardXmlById(string dashboardID) {
return this.LoadDashboard(dashboardID);
}
}
}
C#using AspNetCoreDashboard_ExportAllItems.Classes;
using AspNetCoreDashboard_ExportAllItems.Models;
using DevExpress.DashboardAspNetCore;
using DevExpress.DashboardCommon;
using DevExpress.DashboardWeb;
using DevExpress.Pdf;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace AspNetCoreDashboard_ExportAllItems.Controllers {
public class ExportController : Controller {
[HttpGet]
public FileContentResult ExportAllItems([FromServices] DashboardConfigurator dashboardConfigurator, string dashboardId, string state) {
CustomDashboardStorage storage = dashboardConfigurator.DashboardStorage as CustomDashboardStorage;
Dashboard dashboard = new Dashboard();
dashboard.LoadFromXDocument(storage.GetDashboardXmlById(dashboardId));
MemoryStream resultStream = new MemoryStream();
using (PdfDocumentProcessor documentProcessor = new PdfDocumentProcessor()) {
documentProcessor.CreateEmptyDocument(resultStream);
for (int i = 0; i < dashboard.Items.Count; i++) {
string dashboardItemName = dashboard.Items[i].ComponentName;
DashboardState dashboardState = new DashboardState();
dashboardState.LoadFromJson(state);
WebDashboardExporter exporter = new WebDashboardExporter(dashboardConfigurator);
using (MemoryStream stream = new MemoryStream()) {
exporter.ExportDashboardItemToPdf(dashboardId, dashboardItemName, stream, new System.Drawing.Size(1024, 768), dashboardState);
documentProcessor.AppendDocument(stream);
}
}
}
return File(resultStream.ToArray(), "application/pdf", $"{dashboardId}.pdf");
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AspNetCoreDashboard_ExportAllItems.Models {
public class DashboardExportModel {
public string DashboardId { get; set; }
public string DashboardState { get; set; }
}
}
Razor<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Dashboard Web Application</title>
<link href="css/site.min.css" rel="stylesheet" />
<script type="text/javascript">
function onBeforeRender(sender) {
var dashboardControl = sender;
var exportRoute = '@Url.Action("ExportAllItems", "Export")';
dashboardControl.registerExtension(new ExportAllItemsExtension(dashboardControl, exportRoute));
}
</script>
</head>
<body>
@RenderBody()
<script src="js/site.min.js"></script>
<script src="js/ExportAllItemsExtension.js"></script>
</body>
</html>
Razor@page
<div style="position: absolute; left: 0; top: 0; right: 0; bottom: 0;">
@(Html.DevExpress().Dashboard("dashboardControl1")
.ControllerName("DefaultDashboard")
.Width("100%")
.Height("100%")
.Extensions(extensions => {
extensions.UrlState(urlState => {
urlState.IncludeDashboardIdToUrl(true);
urlState.IncludeDashboardStateToUrl(true);
});
})
.OnBeforeRender("onBeforeRender")
)
</div>