Migrate BI Dashboard from Web Forms to ASP.NET Core
- 6 minutes to read
You can migrate ASP.NET Web Forms Dashboard customizations to a new .NET application. The Dashboard Control API is the same regardless of the target platform, so you can migrate customization code to a new app with minimal adjustments. A custom implementation of ASP.NET Web Forms Dashboard services can also be used in a new application because interface implementation is similar in all web frameworks.
Prerequisites
- .NET 8.0 or later SDK
- Visual Studio 2022 v17.0+
You may require additional packages to run our Dashboard components on Linux or iOS: Linux and MacOS Specifics.
Create an ASP.NET Core Application
In Visual Studio, create a new project as follows:
- On the start page, select ASP.NET Core Web App as the project template.
- In the Configure your new project dialog, enter
WebDashboardAspNetCore
for Project name. - In the Additional information dialog, specify the target framework (.NET 8.0).
Manage Packages and Libraries
Install NuGet Packages
In the project, open the NuGet Package Manager and set the package source to All. Install the following packages:
- DevExpress.AspNetCore.Dashboard
- BuildBundlerMinifier
Refer to the following topic to install and manage libraries using DevExpress NuGet feed: Setup Visual Studio’s NuGet Package Manager.
Install npm Packages
Note
Make sure you have Node.js and npm installed on your machine.
Open the Add New Item dialog (Ctrl+Shift+A
), create the npm Configuration File (package.json), and add the following npm packages:
{
...
"devDependencies": {
"devextreme-dist": "25.1-stable",
"@devexpress/analytics-core": "25.1-stable",
"devexpress-dashboard": "25.1-stable"
}
}
Save package.json, right-click it and select Restore Packages.
Bundle Resources (bundleconfig.json)
Create the bundleconfig.json file in the root directory and add the following configuration:
[
{
"outputFileName": "wwwroot/css/site.min.css",
"inputFiles": [
"node_modules/devextreme-dist/css/dx.light.css",
"node_modules/@devexpress/analytics-core/dist/css/dx-analytics.common.css",
"node_modules/@devexpress/analytics-core/dist/css/dx-analytics.light.css",
"node_modules/@devexpress/analytics-core/dist/css/dx-querybuilder.css",
"node_modules/devexpress-dashboard/dist/css/dx-dashboard.light.min.css"
],
"minify": {
"enabled": false,
"adjustRelativePaths": false
}
},
{
"outputFileName": "wwwroot/css/ace/ace.bundle.css",
"inputFiles": [
"node_modules/ace-builds/css/ace.css",
"node_modules/ace-builds/css/theme/dreamweaver.css",
"node_modules/ace-builds/css/theme/ambiance.css"
],
"minify": {
"enabled": false,
"adjustRelativePaths": false
}
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/knockout/build/output/knockout-latest.js",
"node_modules/ace-builds/src-min-noconflict/ace.js",
"node_modules/ace-builds/src-min-noconflict/ext-language_tools.js",
"node_modules/ace-builds/src-min-noconflict/theme-dreamweaver.js",
"node_modules/ace-builds/src-min-noconflict/theme-ambiance.js",
"node_modules/devextreme-dist/js/dx.all.js",
"node_modules/@devexpress/analytics-core/dist/js/dx-analytics-core.min.js",
"node_modules/@devexpress/analytics-core/dist/js/dx-querybuilder.min.js",
"node_modules/devexpress-dashboard/dist/js/dx-dashboard.min.js"
],
"minify": {
"enabled": false
},
"sourceMap": false
}
]
Create the libman.json file in the root directory of the project and add the following LibMan configuration to copy icon fonts to the application’s static content folder:
{
"version": "1.0",
"defaultProvider": "filesystem",
"libraries": [
{
"library": "node_modules/ace-builds/css/",
"destination": "wwwroot/css/ace",
"files": [ "*.png", "*.svg" ]
},
{
"library": "node_modules/devextreme-dist/css/icons/",
"destination": "wwwroot/css/icons/",
"files": [
"dxicons.ttf",
"dxicons.woff",
"dxicons.woff2"
]
}
]
}
Configure LibMan (libman.json)
Save package.json, right-click it and select Restore Packages.
Create the bundleconfig.json file in the root directory and add the following configuration:
[
{
"outputFileName": "wwwroot/css/site.min.css",
"inputFiles": [
"node_modules/devextreme-dist/css/dx.light.css",
"node_modules/@devexpress/analytics-core/dist/css/dx-analytics.common.css",
"node_modules/@devexpress/analytics-core/dist/css/dx-analytics.light.css",
"node_modules/@devexpress/analytics-core/dist/css/dx-querybuilder.css",
"node_modules/devexpress-dashboard/dist/css/dx-dashboard.light.min.css"
],
"minify": {
"enabled": false,
"adjustRelativePaths": false
}
},
{
"outputFileName": "wwwroot/css/ace/ace.bundle.css",
"inputFiles": [
"node_modules/ace-builds/css/ace.css",
"node_modules/ace-builds/css/theme/dreamweaver.css",
"node_modules/ace-builds/css/theme/ambiance.css"
],
"minify": {
"enabled": false,
"adjustRelativePaths": false
}
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/knockout/build/output/knockout-latest.js",
"node_modules/ace-builds/src-min-noconflict/ace.js",
"node_modules/ace-builds/src-min-noconflict/ext-language_tools.js",
"node_modules/ace-builds/src-min-noconflict/theme-dreamweaver.js",
"node_modules/ace-builds/src-min-noconflict/theme-ambiance.js",
"node_modules/devextreme-dist/js/dx.all.js",
"node_modules/@devexpress/analytics-core/dist/js/dx-analytics-core.min.js",
"node_modules/@devexpress/analytics-core/dist/js/dx-querybuilder.min.js",
"node_modules/devexpress-dashboard/dist/js/dx-dashboard.min.js"
],
"minify": {
"enabled": false
},
"sourceMap": false
}
]
Create the libman.json file in the root directory of the project and add the following LibMan configuration to copy icon fonts to the application’s static content folder:
{
"version": "1.0",
"defaultProvider": "filesystem",
"libraries": [
{
"library": "node_modules/ace-builds/css/",
"destination": "wwwroot/css/ace",
"files": [ "*.png", "*.svg" ]
},
{
"library": "node_modules/devextreme-dist/css/icons/",
"destination": "wwwroot/css/icons/",
"files": [
"dxicons.ttf",
"dxicons.woff",
"dxicons.woff2"
]
}
]
}
Migrate a Dashboard
The CS/VB and XML dashboards are cross-platform and can be reused in any platform dashboard application.
Configure Services on Startup (Program.cs)
All Web Dashboard services that you register using DashboardConfigurator
for ASP.NET Web Forms can be registered in the built-in DI container in ASP.NET Core applications. You do not require to update the signature and definition of services that exist in your legacy ASP.NET Web Forms app. You can copy the implementation of your custom services to your new application as-is. Note that you can use the dependency-injection concept for all migrated services.
The following code snippet registers the DashboardFileStorage
service:
- ASP.NET WebForms
protected void Application_Start(object sender, EventArgs e) { DashboardConfigurator.Default.SetDashboardStorage(new DashboardFileStorage("~/App_Data/Dashboards")); // ... }
- ASP.NET Core
var builder = WebApplication.CreateBuilder(args); builder.Services.AddScoped<DashboardConfigurator>((IServiceProvider serviceProvider) => { DashboardConfigurator configurator = new DashboardConfigurator(); configurator.SetDashboardStorage(new DashboardFileStorage(fileProvider.GetFileInfo("Data/Dashboards").PhysicalPath)); return configurator; }); var app = builder.Build();
The following code snippet references services required by DevExpress BI Dashboard:
using DevExpress.AspNetCore;
using DevExpress.DashboardAspNetCore;
using DevExpress.DashboardWeb;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
IFileProvider? fileProvider = builder.Environment.ContentRootFileProvider;
IConfiguration? configuration = builder.Configuration;
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddDevExpressControls();
builder.Services.AddScoped<DashboardConfigurator>((IServiceProvider serviceProvider) => {
DashboardConfigurator configurator = new DashboardConfigurator();
configurator.SetDashboardStorage(new DashboardFileStorage(fileProvider.GetFileInfo("Data/Dashboards").PhysicalPath));
configurator.SetConnectionStringsProvider(new DashboardConnectionStringsProvider(configuration));
return configurator;
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/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.MapDashboardRoute("api/dashboard", "DefaultDashboard");
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
Migrate Controller Logic
ASP.NET Core apps use the DashboardController class descendant. The dashboard controller handles incoming client requests and maps them to actions on the server.
Note
Some ASP.NET Web Forms applications can process control requests by HTTP handlers registered in the “web.config” file. This option is no longer available. The analogous configuration in ASP.NET Core requires an explicit dashboard controller registration.
- DefaultDashboardController example:
using DevExpress.DashboardAspNetCore; using DevExpress.DashboardWeb; using Microsoft.AspNetCore.DataProtection; namespace WebDashboardAspNetCore.Controllers { public class DefaultDashboardController : DashboardController { public DefaultDashboardController(DashboardConfigurator configurator, IDataProtectionProvider? dataProtectionProvider = null) : base(configurator, dataProtectionProvider) { } } }
Adjust Views
ASP.NET Core uses the DashboardBuilder options to configure the control in a view.
The following code sample displays the Dashboard control and loads a dashboard. The ControllerName
property value is the name of the controller you created earlier (without Controller postfix):
- Web Forms Markup
<dx:ASPxDashboard ID="ASPxDashboard1" runat="server" Width="100%" Height="100%" > <ClientSideEvents BeforeRender="onBeforeRender" /> </dx:ASPxDashboard>
- ASP.NET Core View
@(Html.DevExpress().Dashboard("dashboardControl1") .ControllerName("DefaultDashboard") .Width("100%") .Height("100%") .OnBeforeRender("onBeforeRender") )
Migrate Client-Side Customization
Note
This tutorial is designed for applications that use the unified DashboardControl
API, which simplifies sharing JavaScript code across platforms. Since the code is nearly identical on all supported platforms, we recommend updating your app to use this API before migrating to .NET. For details, see: Migrate from ASPxClientDashboard to DashboardControl API.
Handle the BeforeRender
event to access the underlying DashboardControl
before it is rendered. You can access extensions to customize the Web Dashboard control. The extension is an independent JavaScript module/class that adds specific functionality to the control.
Check the following documentation for more details on how to use Client-Side API in ASP.NET Core application: Client-Side API Overview for ASP.NET Core Dashboard.
The following code snippet registers DashboardPanelExtension
:
- Web Forms Markup
<script type="text/javascript"> function onBeforeRender(sender) { var dashboardControl = sender.GetDashboardControl(); dashboardControl.registerExtension(new DevExpress.Dashboard.DashboardPanelExtension(dashboardControl)); } </script> <dx:ASPxDashboard ID="ASPxDashboard1" runat="server" Width="100%" Height="100%" > <ClientSideEvents BeforeRender="onBeforeRender" /> </dx:ASPxDashboard>
- ASP.NET Core View
<script type="text/javascript"> function onBeforeRender(sender) { var dashboardControl = sender; dashboardControl.registerExtension(new DevExpress.Dashboard.DashboardPanelExtension(dashboardControl)); } </script> @(Html.DevExpress().Dashboard("dashboardControl1") // ... .OnBeforeRender("onBeforeRender") )
Note some functionality specific for the ASP.NET Core platform:
The Init event no longer exists in ASP.NET Core. You can rewrite your customization logic using the
BeforeRender
event.ASP.NET Core uses callbacks which have the only one handler. You cannot use subscription with the
AddHandler
method.