Skip to main content
All docs
V25.1
  • Migrate BI Dashboard from ASP.NET MVC to ASP.NET Core MVC

    • 6 minutes to read

    You can migrate ASP.NET MVC Dashboard Extension 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 MVC Dashboard services can also be used in a new application because interface implementation is similar in all web frameworks.

    Prerequisites

    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:

    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 registered with DashboardConfigurator in an ASP.NET MVC app can be registered in ASP.NET Core’s built-in DI container. You do not need to change the service definitions from your legacy app - just copy them over. Dependency injection works for all migrated services.

    The following code snippet registers the DashboardFileStorage service:

    ASP.NET MVC
    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

    Both ASP.NET MVC and ASP.NET Core apps use the DashboardController class descendant. You can migrate it as is.

    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 the Controller postfix):

    ASP.NET MVC View
    @Html.DevExpress().Dashboard(settings => {
    settings.Name = "dashboardControl1";
    settings.ControllerName = "DefaultDashboard";
    settings.Width = Unit.Percentage(100);
    settings.Height = Unit.Percentage(100);
    settings.ClientSideEvents.BeforeRender = "onBeforeRender";
    }).GetHtml()
    
    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.

    The ASP.NET Core Web Dashboard uses the same client API (DashboardControl) as ASP.NET MVC, with one key difference: in ASP.NET Core, the sender is the DashboardControl itself. In ASP.NET MVC, you need to call GetDashboardControl() first - the rest of the JavaScript code stays the same. These code snippets handles the BeforeRender() method:

    Review the following documentation for more information 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:

    ASP.NET MVC View
    <script type="text/javascript">
      function onBeforeRender(sender) {
        var dashboardControl = sender.GetDashboardControl();
        dashboardControl.registerExtension(new DevExpress.Dashboard.DashboardPanelExtension(dashboardControl));
      }
    </script>
    
    @Html.DevExpress().Dashboard(settings => {
    // ...
    settings.Name = "dashboardControl1";
    settings.ClientSideEvents.BeforeRender = "onBeforeRender";
    }).GetHtml()
    
    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")
    )
    

    The following functionality is specific to the ASP.NET Core platform:

    1. The Init event no longer exists in ASP.NET Core. You can rewrite your customization logic using the BeforeRender event.

    2. ASP.NET Core uses callbacks that have only one handler. You cannot use a subscription with the AddHandler method.

    Useful Resources

    Web Dashboard Technical Overview