Skip to main content

Document Viewer Server-Side Configuration (ASP.NET Core)

  • 6 minutes to read

This document describes how to create and configure an ASP.NET Core application as a server-side solution to use the HTML5 Document Viewer in JavaScript. You can use the DevExpress or Visual Studio template to create an application.

Step 1. Create an ASP.NET Core Application

Use DevExpress Template or Microsoft Visual Studio Template to create a new project.

Use DevExpress Template

You can use the Template Gallery to create a new ASP.NET Core project as follows:

  1. Invoke the DevExpress Template Gallery, select Reporting Application under the .NET category and click Create Project.

    create-new-aspnet-core-reporting-application-template-gallery

  2. Set Add Viewer Page to true to add the Document Viewer to the web application.

    web-reporting-project-wizard-select-viewer

Note

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

Refer to the following help topic for details: Create an ASP.NET Core Application with the Document Viewer.

Use Microsoft Visual Studio Template

You can create an ASP.NET Core application based on the built-in Visual Studio template and configure it for the DevExpress Document Viewer as follows:

  1. Create a new ASP.NET Core Web Application (or open an existing application).

    Create New ASP.NET Core Application

  2. Right-click the Dependencies node in the Solution Explorer and select Manage NuGet Packages in the invoked context menu.

    Install NuGet Packages

  3. Select DevExpress <:xx.x: Local in the Package source drop-down list and go to the Browse page. Find the DevExpress.AspNetCore.Reporting package and install it.

  4. Open the Program.cs file and and modify it to configure services as demonstrated below:

    using DevExpress.AspNetCore;
    //...
    
    var builder = WebApplication.CreateBuilder(args);
    //...
    // Register reporting services in an application's dependency injection container.
    builder.Services.AddDevExpressControls();
    // Use the AddMvcCore (or AddMvc) method to add MVC services.
    builder.Services.AddMvcCore(); 
    //...
    var app = builder.Build();
    
    // Initialize reporting services.
    app.UseDevExpressControls();
    // ...
    
  5. Implement a controller to process Document Viewer requests. In the Controllers folder, create the ReportingControllers.cs file with the following content:

    using DevExpress.AspNetCore.Reporting.WebDocumentViewer;
    using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services;
    
    namespace WebApplication1.Controllers {
        public class CustomWebDocumentViewerController : WebDocumentViewerController {
            public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService)
                : base(controllerService) {
            }
        }
    }
    
  6. Add reports to the application.

  7. Add a server-side report storage. To implement a report storage, add a new class inherited from the ReportStorageWebExtension class as described in the ReportStorageWebExtension help topic. Refer to the following help topic for more information and report storage examples: Add a Report Storage (ASP.NET Core).

    using System.ServiceModel;
    using DevExpress.XtraReports.UI;
    public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension {
       readonly string reportDirectory = "Reports";
       const string FileExtension = ".repx";
    
       public CustomReportStorageWebExtension() {
             if (!Directory.Exists(reportDirectory)) {
                Directory.CreateDirectory(reportDirectory);
             }
       }
       public CustomReportStorageWebExtension(string reportDirectory) {
             if (!Directory.Exists(reportDirectory)) {
                Directory.CreateDirectory(reportDirectory);
             }
             this.reportDirectory = reportDirectory;
       }
    
       private bool IsWithinReportsFolder(string url, string folder) {
             var rootDirectory = new DirectoryInfo(folder);
             var fileInfo = new FileInfo(Path.Combine(folder, url));
             return fileInfo.Directory.FullName.ToLower().StartsWith(rootDirectory.FullName.ToLower());
       }
    
       public override bool CanSetData(string url) {
             // Determines whether a report with the specified URL can be saved.
             // Add custom logic that returns **false** for reports that should be read-only.
             // Return **true** if no valdation is required.
             // This method is called only for valid URLs (if the **IsValidUrl** method returns **true**).
    
             return true;
       }
    
       public override bool IsValidUrl(string url) {
             // Determines whether the URL passed to the current report storage is valid.
             // Implement your own logic to prohibit URLs that contain spaces or other specific characters.
             // Return **true** if no validation is required.
    
             return Path.GetFileName(url) == url;
       }
    
       public override byte[] GetData(string url) {
             // Uses a specified URL to return report layout data stored within a report storage medium.
             // This method is called if the **IsValidUrl** method returns **true**.
             // You can use the **GetData** method to process report parameters sent from the client
             // if the parameters are included in the report URL's query string.
             try {
                if (Directory.EnumerateFiles(reportDirectory).Select(Path.GetFileNameWithoutExtension).Contains(url)) {
                   return File.ReadAllBytes(Path.Combine(reportDirectory, url + FileExtension));
                }
                if (ReportsFactory.Reports.ContainsKey(url)) {
                   using (MemoryStream ms = new MemoryStream()) {
                         ReportsFactory.Reports[url]().SaveLayoutToXml(ms);
                         return ms.ToArray();
                   }
                }
             }
             catch (Exception) {
                throw new FaultException(new FaultReason("Could not get report data."), new FaultCode("Server"), "GetData");
             }
             throw new FaultException(new FaultReason(string.Format("Could not find report '{0}'.", url)), new FaultCode("Server"), "GetData");
       }
    
       public override Dictionary<string, string> GetUrls() {
             // Returns a dictionary that contains the report names (URLs) and display names. 
             // The Report Designer uses this method to populate the Open Report and Save Report dialogs.
    
             return Directory.GetFiles(reportDirectory, "*" + FileExtension)
                                     .Select(Path.GetFileNameWithoutExtension)
                                     .Union(ReportsFactory.Reports.Select(x => x.Key))
                                     .ToDictionary<string, string>(x => x);
       }
    
       public override void SetData(XtraReport report, string url) {
             // Saves the specified report to the report storage with the specified name
             // (saves existing reports only). 
             if (!IsWithinReportsFolder(url, reportDirectory))
                throw new FaultException(new FaultReason("Invalid report name."), new FaultCode("Server"), "GetData");
             report.SaveLayoutToXml(Path.Combine(reportDirectory, url + FileExtension));
       }
    
       public override string SetNewData(XtraReport report, string defaultUrl) {
             // Allows you to validate and correct the specified name (URL).
             // This method also allows you to return the resulting name (URL),
             // and to save your report to a storage. The method is called only for new reports.
             SetData(report, defaultUrl);
             return defaultUrl;
       }
    } 
    
    public static class ReportsFactory
    {
       public static Dictionary<string, Func<XtraReport>> Reports = new Dictionary<string, Func<XtraReport>>()
       {
             ["TestReport"] = () => new TestReport()
       };
    }
    
  8. Register the report storage implemented in the previous step as a scoped service. Open the Program.cs file and add the following code :

    using DevExpress.XtraReports.Web.Extensions;
    // ...
    builder.Services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>();
    //...
    

Step 2. Configure the Application

Enable cross-origin requests (CORS) in the newly created ASP.NET Core application. Specify the policy that allows any local application to access the report’s back-end. Use the SetIsOriginAllowed method to set it up.

Call the UseCors method and pass the policy name as a parameter. The UseCors method should be called after the UseRouting method and before any MVC-related code. Place the UseCors method before the UseMvc or UseEndpoints methods.

Open the application startup file and insert the following code:

var builder = WebApplication.CreateBuilder(args);

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();

app.UseRouting();
app.UseCors("AllowCorsPolicy");

app.UseEndpoints(endpoints => {
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

app.Run();

Step 3. Determine the Host URL

Examine the address string in the browser to determine the host URL and application port.

You can use the Debug section of the Project Properties dialog to view and change the port number:

If you do not use Visual Studio to run the project, inspect the launchSettings.json file. If your application uses HTTPS redirection and calls the UseHttpsRedirection method at startup, the port number is specified in the sslPort setting.

The URL and port number are required for the host setting when you configure the client application as described in the following help topics:

See Also