# Devexpress Reports Aspnetcore

> >

- **Type:** Skill
- **Install:** `agentstack add skill-devexpress-agent-skills-devexpress-reports-aspnetcore`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [DevExpress](https://agentstack.voostack.com/s/devexpress)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [DevExpress](https://github.com/DevExpress)
- **Source:** https://github.com/DevExpress/agent-skills/tree/main/plugins/dx-reporting/skills/devexpress-reports-aspnetcore
- **Website:** https://www.devexpress.com

## Install

```sh
agentstack add skill-devexpress-agent-skills-devexpress-reports-aspnetcore
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# DevExpress ASP.NET Core Reporting — Viewer & Designer Integration

Integrates the DevExpress Web Document Viewer (read-only preview) and Web Report Designer (full end-user designer) into ASP.NET Core MVC and Razor Pages applications. The viewer renders reports in the browser via server-side document generation; the designer lets end-users create and save reports without developer involvement.

This skill covers **UI component integration only**. For creating reports programmatically (bands, controls, data binding, expressions, export), use the `devexpress-reports-core` skill.

## When to Use This Skill

- Add a Document Viewer to an ASP.NET Core MVC or Razor Pages application
- Add an End-User Report Designer to an ASP.NET Core application
- Configure Program.cs services and middleware for reporting
- Set up npm bundling (bundleconfig.json, libman.json) for reporting assets
- Implement `ReportStorageWebExtension` or `IReportProvider`
- Customize viewer/designer toolbar, tab panel, export options, parameter editors
- Configure security: authorization, CSRF protection, CSP nonce
- Deploy reporting to Linux or macOS (Skia renderer setup)
- Troubleshoot blank viewers, HTTP errors, or script loading failures
- Set up multi-server (web farm/garden) document storage

## Prerequisites & Installation

### NuGet Packages

| Package | Purpose |
|---------|---------|
| `DevExpress.AspNetCore.Reporting` | Document Viewer + Report Designer server-side |
| `BuildBundlerMinifier` | Bundles npm output into wwwroot/ |
| `Microsoft.Web.LibraryManager.Build` | Copies icon fonts to wwwroot/ |
| `DevExpress.Drawing.Skia` | **Required** on Linux and macOS hosts |

### npm Packages (package.json)

```json
{
  "dependencies": {
    "bootstrap": "^4.3.1",
    "devextreme-dist": "26.1-stable",
    "@devexpress/analytics-core": "26.1-stable",
    "devexpress-reporting": "26.1-stable"
  }
}
```

> **npm and NuGet versions must match.** All DevExpress packages — both npm and NuGet — must use the same major.minor version (e.g., `26.1`). A mismatch causes `configurator.UseDevelopmentMode()` to report version errors and the viewer to silently fail.

### Mandatory Setup Order

Complete all steps in order before running the app. Missing any step causes the viewer/designer to fail silently or throw 500 errors.

**Step 1 — Install NuGet packages** (`DevExpress.AspNetCore.Reporting`, `BuildBundlerMinifier`, `Microsoft.Web.LibraryManager.Build`)

**Step 2 — Install Node.js** (LTS) if not already installed

**Step 3 — Add package.json** with npm dependencies above; right-click → Restore Packages or run `npm install`. npm install **must complete before** `dotnet build` — LibMan's filesystem provider requires `node_modules` to exist.

**Step 4 — Add bundleconfig.json** (see [references/getting-started.md](references/getting-started.md) for full content). This defines CSS/JS bundles that are copied to `wwwroot/` at build time.

**Step 5 — Add libman.json** (see [references/getting-started.md](references/getting-started.md)) to copy icon font files to `wwwroot/css/icons/`.

**Step 6 — Program.cs** — add three lines:
```csharp
using DevExpress.AspNetCore;
using DevExpress.AspNetCore.Reporting; // required for ConfigureReportingServices

builder.Services.AddDevExpressControls();
builder.Services.ConfigureReportingServices(configurator => {
    configurator.ConfigureWebDocumentViewer(c => c.UseCachedReportSourceBuilder());
});
// ... (after builder.Build())
app.UseDevExpressControls(); // must come BEFORE app.UseStaticFiles()
app.UseStaticFiles();
```

**Step 7 — Add controllers** (see Component Overview below)

**Step 8 — _ViewImports.cshtml**:
```cshtml
@using DevExpress.AspNetCore
```

**Step 9 — _Layout.cshtml** — add thirdparty bundle to ``:
```cshtml

```

**Step 10 — View file** — add reporting bundle + HTML helper (see Component Overview)

## Before You Start — Ask the Developer

Before generating code, ask:

1. **Component**: Document Viewer only, or also End-User Report Designer?
2. **App template**: MVC (Model-View-Controller) or Razor Pages?
3. **Report source**: Instance binding (`new MyReport()`) for quickstart, or storage-backed (`ReportStorageWebExtension`) for load/save by name?
4. **Target OS**: Windows, Linux, or macOS? (Skia package required for non-Windows)
5. **Existing project or new?** If existing, check for conflicting npm packages (jQuery, Knockout, Bootstrap, DevExtreme) already in bundleconfig.json.
6. **Security**: Is authorization required on the reporting endpoints?

## Component Overview

### Document Viewer (read-only)

Requires: 1 controller, viewer-specific bundles.

```csharp
// Controllers/ReportingControllers.cs
using DevExpress.AspNetCore.Reporting.WebDocumentViewer;
using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services;

public class CustomWebDocumentViewerController : WebDocumentViewerController {
    public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService s)
        : base(s) { }
}
```

```cshtml
@* Views/Home/Index.cshtml — viewer page *@

@Html.DevExpress().WebDocumentViewer("DocumentViewer").Height("1000px").Bind(new TestReport())
```

### End-User Report Designer

Requires: 3 controllers + `ReportStorageWebExtension`, designer-specific bundles.

```csharp
// Controllers/ReportingControllers.cs — all three required
using DevExpress.AspNetCore.Reporting.QueryBuilder;
using DevExpress.AspNetCore.Reporting.QueryBuilder.Native.Services;
using DevExpress.AspNetCore.Reporting.ReportDesigner;
using DevExpress.AspNetCore.Reporting.ReportDesigner.Native.Services;
using DevExpress.AspNetCore.Reporting.WebDocumentViewer;
using DevExpress.AspNetCore.Reporting.WebDocumentViewer.Native.Services;

public class CustomWebDocumentViewerController : WebDocumentViewerController {
    public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService s) : base(s) { }
}
public class CustomReportDesignerController : ReportDesignerController {
    public CustomReportDesignerController(IReportDesignerMvcControllerService s) : base(s) { }
}
public class CustomQueryBuilderController : QueryBuilderController {
    public CustomQueryBuilderController(IQueryBuilderMvcControllerService s) : base(s) { }
}
```

```cshtml
@* Views/Home/Index.cshtml — designer page *@

@(Html.DevExpress().ReportDesigner("reportDesigner")
    .Height("1000px")
    .Bind(new TestReport()))
```

> **Critical**: For multi-line fluent chains, always wrap in `@(...)`. Without it, trailing method calls render as literal text in the page output.
>
> **Critical**: Do NOT load `viewer.part.bundle.js` on a designer page. The designer bundle already includes the viewer scripts. Loading both causes `Component dx-filtereditor-plain is already registered` and `DxReportDesigner undefined`.

## Documentation & Navigation Guide

### Full MVC Setup (bundleconfig.json, libman.json, Program.cs, controllers, views)
📄 [references/getting-started.md](references/getting-started.md)
📄 [references/getting-started-razor-pages.md](references/getting-started-razor-pages.md)

### Report Storage and Name Resolution (ReportStorageWebExtension, IReportProvider)
📄 [references/report-storage.md](references/report-storage.md)

When you need to: enable Save/Load/Open in the designer; serve reports by name string; use `Bind("ReportName")` vs. `Bind(new Report())`.

### Viewer Customization (toolbar, tab panel, export options, parameters, client-side events)
📄 [references/viewer-customization.md](references/viewer-customization.md)

### Designer Customization (toolbar, toolbox, wizards, data sources, parameter editing)
📄 [references/designer-customization.md](references/designer-customization.md)

### Security (authorization, CSRF, CSP nonce, token auth, multi-tenancy)
📄 [references/security.md](references/security.md)

### Troubleshooting (symptom→fix table, development mode, logging, web farms)
📄 [references/troubleshooting.md](references/troubleshooting.md)

## Quick Start Example

See [examples/quickstart-viewer.cs](examples/quickstart-viewer.cs) and [examples/quickstart-designer.cs](examples/quickstart-designer.cs) for complete, runnable projects.

Minimal Program.cs (MVC, Document Viewer):
```csharp
using DevExpress.AspNetCore;
using DevExpress.AspNetCore.Reporting;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddDevExpressControls();
builder.Services.ConfigureReportingServices(configurator => {
    if (builder.Environment.IsDevelopment())
        configurator.UseDevelopmentMode();
    configurator.ConfigureWebDocumentViewer(c => c.UseCachedReportSourceBuilder());
});

var app = builder.Build();
app.UseDevExpressControls();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
app.Run();
```

## Key API Surface

### Program.cs Registration

| Method | Namespace | Purpose |
|--------|-----------|---------|
| `AddDevExpressControls()` | `DevExpress.AspNetCore` | Register core DX services |
| `ConfigureReportingServices(Action)` | `DevExpress.AspNetCore.Reporting` | Register viewer/designer services |
| `UseDevExpressControls()` | `DevExpress.AspNetCore` | Add middleware — **before UseStaticFiles** |
| `UseCachedReportSourceBuilder()` | (on `WebDocumentViewerConfigurationBuilder`) | Enable document caching |
| `UseDevelopmentMode()` | (on `ReportingConfigurationBuilder`) | Verbose error output + version check |

### Controller Routes

| Controller | Route | Required For |
|-----------|-------|-------------|
| `WebDocumentViewerController` | `DXXRDV` | Viewer + Designer |
| `ReportDesignerController` | `DXXRD` | Designer only |
| `QueryBuilderController` | `DXXQB` | Designer only |

### Report Name Resolution (choose one)

| Service | Use When |
|---------|---------|
| `IReportProvider` | Viewer-only; map name → `XtraReport` instance |
| `ReportStorageWebExtension` | Designer present; full save/load/list |
| `IWebDocumentViewerReportResolver` | Highest priority; viewer-only; no async support |

## Common Patterns

### Pattern 1: Serve a report by name (IReportProvider)

```csharp
// Services/ReportProvider.cs
using DevExpress.XtraReports.Services;

public class ReportProvider : IReportProvider {
    public XtraReport GetReport(string id, ReportProviderContext context) {
        return id switch {
            "SalesReport" => new SalesReport(),
            "InvoiceReport" => new InvoiceReport(),
            _ => throw new InvalidOperationException($"Report '{id}' not found.")
        };
    }
}

// Program.cs
builder.Services.AddScoped();
```

```cshtml
@Html.DevExpress().WebDocumentViewer("DocumentViewer").Height("1000px").Bind("SalesReport")
```

### Pattern 2: Async export from a controller action

```csharp
public async Task ExportPdf(string reportName) {
    var report = new SalesReport();
    report.RequestParameters = false;
    await report.CreateDocumentAsync(); // never use CreateDocument() in web apps
    using var stream = new MemoryStream();
    report.ExportToPdf(stream);
    return File(stream.ToArray(), "application/pdf", "report.pdf");
}
```

### Pattern 3: Pass parameters to viewer at load time

```cshtml
@Html.DevExpress().WebDocumentViewer("DocumentViewer")
    .Height("1000px")
    .Bind("SalesReport?StartDate=2025-01-01&Region=North")
```

```csharp
// In IReportProvider.GetReport — parse and apply:
public XtraReport GetReport(string id, ReportProviderContext context) {
    var uri = new Uri("http://x/" + id);
    var qs = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query);
    var report = new SalesReport();
    var startDateValue = qs["StartDate"];
    if (!string.IsNullOrWhiteSpace(startDateValue) &&
        DateTime.TryParse(startDateValue, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var startDate))
        report.Parameters["StartDate"].Value = startDate;
    report.Parameters["StartDate"].Visible = false;
    return report;
}
```

## Troubleshooting

| Symptom | Cause | Fix |
|---------|-------|-----|
| Viewer blank, no errors in console | `UseDevExpressControls()` missing or after `UseStaticFiles()` | Move `app.UseDevExpressControls()` before `app.UseStaticFiles()` |
| "Unable to process binding" in browser | Script load order wrong — DevExtreme or Analytics not loaded before viewer init | Ensure `thirdparty.bundle.js` loads in layout ``, not in `@section Scripts {}` |
| `Component dx-filtereditor-plain is already registered` | Both viewer and designer bundles loaded on designer page | Remove viewer bundle from designer page — designer bundle includes viewer scripts |
| `DevExpress is not defined` | `dx.all.js` missing from bundle or loaded after reporting scripts | Verify `dx.all.js` is first entry in `designer.part.bundle.js` / `viewer.part.bundle.js` |
| Literal fluent-call text in page (e.g. `.Height("...")`) | Multi-line Razor helper not wrapped in `@(...)` | Wrap: `@(Html.DevExpress().ReportDesigner(...).Height(...).Bind(...))` |
| HTTP 400 on DXXRDV | Anti-forgery token rejection | Add `[IgnoreAntiforgeryToken]` to viewer/designer controllers |
| HTTP 404 on DXXRDV / DXXRD | Controller missing or `MapDefaultControllerRoute()` absent | Add controllers; in Razor Pages apps also call `endpoints.MapDefaultControllerRoute()` |
| HTTP 500, no details | Server exception; development mode off | Add `configurator.UseDevelopmentMode()` and set `"DevExpress": "Debug"` in appsettings.json |
| `DllNotFoundException` for Skia at runtime | Missing `DevExpress.Drawing.Skia` on Linux/macOS | `dotnet add package DevExpress.Drawing.Skia` |
| "Report not found: ReportName" | Designer binding by name with no storage resolving it | Use `Bind(new MyReport())` for quickstart, or implement `ReportStorageWebExtension.GetData("ReportName")` |
| `FaultException` compile error in storage class | WCF type used in storage; not available in ASP.NET Core | Replace `FaultException` with `InvalidOperationException` |
| npm package version ≠ NuGet version | `devextreme-dist` or `@devexpress/analytics-core` version mismatch | Align all to same major.minor (26.1). Enable `UseDevelopmentMode()` to confirm. |
| Build error: `libman.json` file not found | npm install did not run before build | Run `npm install` first; LibMan filesystem provider requires `node_modules` |
| `ko is not defined` in browser console | Knockout missing from bundle or loaded after `dx.all.js` | Ensure `knockout-latest.js` is in `thirdparty.bundle.js` **before** `dx.all.js` in `viewer.part.bundle.js`. Order: jQuery → Knockout → Bootstrap → (then) dx.all.js → analytics-core → webdocumentviewer |
| `DevExtreme library is included before Knockout` warning in console | `dx.all.js` loads before Knockout | Move Knockout into `thirdparty.bundle.js` (first bundle, loaded in layout ``). `dx.all.js` must come after Knockout — it goes in `viewer.part.bundle.js` (loaded per-page) |

## Constraints & Rules

CRITICAL — follow in every interaction:

1. **Build verification**: Run `dotnet build --project ` after changes. Do not report success without seeing a clean build.
2. **npm before build**: Run `npm install` before `dotnet build` when `libman.json` uses the filesystem provider. `node_modules` must exist for LibMan to copy icon files.
3. **Namespace for ConfigureReportingServices**: Always add `using DevExpress.AspNetCore.Reporting;`. Without it, `ConfigureReportingServices` is not resolved.
4. **UseDevExpressControls order**: Must come before `app.UseStaticFiles()`. Reversing this causes the viewer to silently fail.
5. **Designer bundle self-containment**: `designer.part.bundle.js` must include `dx.all.js` + `dx-analytics-core.min.js` + `dx-webdocumentviewer.min.js` + `dx-querybuilder.min.js` + `dx-reportdesigner.min.js` — all in that order. Do not load a separate viewer bundle on the designer page.
6. **Thirdparty bundle in layout head**: `thirdparty.bundle.js`

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [DevExpress](https://github.com/DevExpress)
- **Source:** [DevExpress/agent-skills](https://github.com/DevExpress/agent-skills)
- **License:** MIT
- **Homepage:** https://www.devexpress.com

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-devexpress-agent-skills-devexpress-reports-aspnetcore
- Seller: https://agentstack.voostack.com/s/devexpress
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
