Report Designer Server-Side Configuration (ASP.NET MVC)

  • 6 minutes to read

This document describes how to create and configure an ASP.NET MVC application as a server-side solution to use the End-User Web Report Designer in JavaScript:

NOTE

The complete sample project is available in the following DevExpress Examples repository on GitHub: How to Perform the JavaScript Report Designer Integration (with npm or Yarn package managers).

  1. Use the Template Gallery to create a new ASP.NET MVC project.

    NOTE

    To add reporting functionality to an existing MVC application, register the required extensions as described in the following help topic: How to Integrate ASP.NET MVC Reporting Extensions Into an Existing Project.

  2. Create custom MVC controllers and inherit them from the following classes:

    • WebDocumentViewerApiController

      Show content
      using DevExpress.Web.Mvc.Controllers;
      using System.Web.Mvc;
      
      namespace DXWebApplication1.Controllers
      {
        public class WebDocumentViewerController : WebDocumentViewerApiController
        {
            //
            // GET: /WebDocumentViewer/
      
            public override ActionResult Invoke()
            {
                var result = base.Invoke();
                // Allow cross-domain requests.
                Response.AppendHeader("Access-Control-Allow-Origin", "*");
                return result;
            }
      
        }
      } 
      
    • ReportDesignerApiController

      Show content
      using DevExpress.DataAccess.Sql;
      using DevExpress.Web.Mvc.Controllers;
      using DevExpress.XtraReports.Web.ReportDesigner;
      using System.Collections.Generic;
      using System.Web.Mvc;
      
      namespace DXWebApplication1.Controllers
      {
        public class ReportDesignerController : ReportDesignerApiController
        {
            public override ActionResult Invoke()
            {
                var result = base.Invoke();
                // Allow cross-domain requests.
                Response.AppendHeader("Access-Control-Allow-Origin", "*");
                return result;
            }
      
            public ActionResult GetReportDesignerModel(string reportUrl)
            {
                Response.AppendHeader("Access-Control-Allow-Origin", "*");
      
                string modelJsonScript =
                    new ReportDesignerClientSideModelGenerator()
                    .GetJsonModelScript(
                        reportUrl,                 // The URL of a report that is opened in the Report Designer when the application starts.
                        GetAvailableDataSources(), // Available data sources in the Report Designer that can be added to reports.
                        "ReportDesigner/Invoke",   // The URI path of the controller action that processes requests from the Report Designer.
                        "WebDocumentViewer/Invoke",// The URI path of the controller action that processes requests from the Web Document Viewer.
                        "QueryBuilder/Invoke"      // The URI path of the controller action that processes requests from the Query Builder.
                    );
                return Content(modelJsonScript, "application/json");
            }
      
            Dictionary<string, object> GetAvailableDataSources()
            {
                var dataSources = new Dictionary<string, object>();
                SqlDataSource ds = new SqlDataSource("NWindConnectionString");
                var query = SelectQueryFluentBuilder.AddTable("Products").SelectAllColumns().Build("Products");
                ds.Queries.Add(query);
                ds.RebuildResultSchema();
                dataSources.Add("SqlDataSource", ds);
                return dataSources;
            }
        }
      }
      
    • QueryBuilderApiController

      Show content
      using DevExpress.Web.Mvc.Controllers;
      using System.Web.Mvc;
      
      namespace DXWebApplication1.Controllers
      {
        public class QueryBuilderController : QueryBuilderApiController
        {
            //
            // GET: /QueryBuilder/
      
            public override ActionResult Invoke()
            {
                var result = base.Invoke();
                // Allow cross-domain requests.
                Response.AppendHeader("Access-Control-Allow-Origin", "*");
                return result;
            }
      
        }
      }
      
  3. The Invoke action allows cross-domain requests:

    using System.Web.Mvc;
    using DevExpress.Web.Mvc.Controllers;
    //...
    
    public class ReportDesignerController : ReportDesignerApiController {
        //...
        public override ActionResult Invoke() {
            var result = base.Invoke();
            Response.AppendHeader("Access-Control-Allow-Origin", "*");
            return result;
        }
    }
    
    TIP

    You can override the GetLocalization action to customize localization strings.

  4. The project template contains the ReportStorageWebExtension class descendant that implements a server-side report storage.

    NOTE

    The template generates a sample storage (a ReportStorageWebExtension descendant) for demonstration purposes only. Create your own implementation for use in production.

    using DevExpress.XtraReports.Web.Extensions;
    
    public class MyReportStorage : ReportStorageWebExtension {
       // ...
    }
    

    At application startup, the static ReportStorageWebExtension.RegisterExtensionGlobal method registers the custom web report storage:

    using DevExpress.XtraReports.Web.Extensions;
    
    protected void Application_Start() {
        // ...
        ReportStorageWebExtension.RegisterExtensionGlobal(new MyReportStorage());
    }
    
  5. The ReportDesignerApiController implementation includes an action to create the Report Designer model. This action uses the ReportDesignerClientSideModelGenerator class and provides the following initialization data:

    • A report URL (required);
    • Available data sources (optional);
    • URIs for reporting controllers' Invoke actions (required).
    using System.Web.Mvc;
    using DevExpress.Web.Mvc.Controllers;
    using DevExpress.XtraReports.Web.ReportDesigner;
    //...
    
    public class ReportDesignerController : ReportDesignerApiController {
        //...
         public ActionResult GetReportDesignerModel(string reportUrl) {
             Response.AppendHeader("Access-Control-Allow-Origin", "*");
    
             string modelJsonScript =
                 new ReportDesignerClientSideModelGenerator()
                 .GetJsonModelScript(
                     reportUrl,                 // The URL of a report that is opened in the Report Designer when the application starts.
                     GetAvailableDataSources(), // Available data sources in the Report Designer that can be added to reports.
                     "ReportDesigner/Invoke",   // The URI path of the controller action that processes requests from the Report Designer.
                     "WebDocumentViewer/Invoke",// The URI path of the controller action that processes requests from the Web Document Viewer.
                     "QueryBuilder/Invoke"      // The URI path of the controller action that processes requests from the Query Builder.
                 );
             return Content(modelJsonScript, "application/json");
         }
    }
    
  6. The GetAvailableDataSources method specified in the model settings above creates data sources for the Report Designer:

    using System.Web.Mvc;
    using System.Collections.Generic;
    using DevExpress.Web.Mvc.Controllers;
    using DevExpress.DataAccess.Sql;
    
    public class ReportDesignerController : ReportDesignerApiController {
        // ...
    
        Dictionary<string, object> GetAvailableDataSources() {
            var dataSources = new Dictionary<string, object>();
            SqlDataSource ds = new SqlDataSource("NWindConnectionString");
            var query = SelectQueryFluentBuilder.AddTable("Products").SelectAllColumns().Build("Products");
            ds.Queries.Add(query);
            ds.RebuildResultSchema();
            dataSources.Add("SqlDataSource", ds);
            return dataSources;
        }
    }
    
See Also