This example integrates the End-User Report Designer into an ASP.NET WebForms application and implements a Microsoft SQL Server database report storage to add, edit and delete reports. This example also demonstrates how to add custom commands to the report designer menu at runtime. A custom Close menu command redirects the user to the homepage.
Before you start
Create Reports Database
Create a Reports database in the local Microsoft SQL Server. Add the ReportLayout table with the following script:
SQL
SQLUSE [Reports]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ReportLayout](
[ReportId] [int] IDENTITY(1,1) NOT NULL,
[DisplayName] [nvarchar] NULL,
[LayoutData] [varbinary] NULL,
[ReportId] ASC
CONSTRAINT [PK_ReportLayout6] PRIMARY KEY CLUSTERED
(
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SQL Server 2016 - v13.0.x.x
SQLUSE [Reports]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ReportLayout](
[ReportId] [int] IDENTITY(1,1) NOT NULL ,
[DisplayName] [nvarchar](50) NULL,
[LayoutData] [varbinary](max) NULL,
CONSTRAINT PK_ReportLayout PRIMARY KEY (ReportId)
);
SELECT *
FROM [dbo].[ReportLayout]
ORDER BY [ReportId] ASC
GO
Create Northwind Database
Create the Northwind database and add it to your local Microsoft SQL server.
Files to Review
- CustomReportStorageWebExtension.cs (VB: CustomReportStorageWebExtension.vb)
- Default.aspx (VB: Default.aspx)
- Default.aspx.cs (VB: Default.aspx.vb)
- Designer.aspx (VB: Designer.aspx)
- Designer.aspx.cs (VB: Designer.aspx.vb)
- DesignerTask.cs (VB: DesignerTask.vb)
- Global.asax.cs (VB: Global.asax.vb)
Documentation
- Create an ASP.NET Web Forms Application with a Report Designer
- Add a Report Storage (ASP.NET Web Forms)
- End-User Report Designer Customization (ASP.NET Web Forms)
More Examples
- How to Integrate Web Report Designer in an MVC Web Application
- Reporting for Web Forms - Report Designer with the ASPxFileManager Control in the Open Report Dialog
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using DevExpress.XtraReports.UI;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
namespace SimpleWebReportCatalog
{
public class CustomReportStorageWebExtension :
DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
{
private DataTable reportsTable = new DataTable();
private SqlDataAdapter reportsTableAdapter;
public CustomReportStorageWebExtension()
{
string connectionString = ConfigurationManager.ConnectionStrings["catalogConnectionString"].ConnectionString;
reportsTableAdapter =
new SqlDataAdapter("Select * from ReportLayout", new SqlConnection(connectionString));
SqlCommandBuilder builder = new SqlCommandBuilder(reportsTableAdapter);
reportsTableAdapter.InsertCommand = builder.GetInsertCommand();
reportsTableAdapter.UpdateCommand = builder.GetUpdateCommand();
reportsTableAdapter.DeleteCommand = builder.GetDeleteCommand();
reportsTableAdapter.Fill(reportsTable);
DataColumn[] keyColumns = new DataColumn[1];
keyColumns[0] = reportsTable.Columns[0];
reportsTable.PrimaryKey = keyColumns;
}
public override bool CanSetData(string url)
{
return GetUrls()[url].Contains("ReadOnly") ? false : true;
}
public override byte[] GetData(string url)
{
// Get the report data from the storage.
DataRow row = reportsTable.Rows.Find(int.Parse(url));
if (row == null) return null;
byte[] reportData = (Byte[])row["LayoutData"];
return reportData;
}
public override Dictionary<string, string> GetUrls()
{
reportsTable.Clear();
reportsTableAdapter.Fill(reportsTable);
// Get URLs and display names for all reports available in the storage.
var v = reportsTable.AsEnumerable()
.ToDictionary<DataRow, string, string>(dataRow => ((Int32)dataRow["ReportId"]).ToString(),
dataRow => (string)dataRow["DisplayName"]);
return v;
}
public override bool IsValidUrl(string url)
{
return true;
}
public override void SetData(XtraReport report, string url)
{
// Write a report to the storage under the specified URL.
DataRow row = reportsTable.Rows.Find(int.Parse(url));
if (row != null)
{
using (MemoryStream ms = new MemoryStream())
{
report.SaveLayoutToXml(ms);
row["LayoutData"] = ms.GetBuffer();
}
reportsTableAdapter.Update(reportsTable);
}
}
public override string SetNewData(XtraReport report, string defaultUrl)
{
// Append "1" if a new report name already exists.
if (GetUrls().ContainsValue(defaultUrl)) defaultUrl = string.Concat(defaultUrl,"1");
// Save a report to the storage with a new URL.
// The defaultUrl parameter is the report name that the user specifies.
DataRow row = reportsTable.NewRow();
row["ReportId"] = 0;
row["DisplayName"] = defaultUrl;
using (MemoryStream ms = new MemoryStream())
{
report.SaveLayoutToXml(ms);
row["LayoutData"] = ms.GetBuffer();
}
reportsTable.Rows.Add(row);
reportsTableAdapter.Update(reportsTable);
// Refill the dataset to obtain the actual value of the new row's autoincrement key field.
reportsTable.Clear();
reportsTableAdapter.Fill(reportsTable);
return reportsTable.AsEnumerable().
FirstOrDefault(x => x["DisplayName"].ToString() == defaultUrl)["ReportId"].ToString();
}
}
}
ASPx<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SimpleWebReportCatalog.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="CatalogForm" runat="server">
<div>
<h1>Report Catalog </h1>
<p>Use the form below to manage reports in the catalog.</p>
</div>
<div>
<asp:ListBox ID="reportsList" runat="server" Width="600px" Height="150px"></asp:ListBox>
</div>
<div>
<asp:Button CssClass="catalogButton" ID="editButton" runat="server" Text="Edit"
OnClick="EditButton_Click" />
<asp:Button CssClass="catalogButton" ID="deleteButton" runat="server" Text="Delete"
OnClick="DeleteButton_Click" />
</div>
<hr />
<div>
<asp:Button CssClass="catalogButton" ID="newReportButton" runat="server"
Text="New Report" OnClick="NewReportButton_Click" />
</div>
</form>
</body>
</html>
C#using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web.UI.WebControls;
// ...
namespace SimpleWebReportCatalog {
public partial class Default : System.Web.UI.Page {
private DataTable reportsTable = new DataTable();
private SqlDataAdapter reportsTableAdapter;
protected void Page_Load(object sender, EventArgs e) {
string connectionString = ConfigurationManager.ConnectionStrings["catalogConnectionString"].ConnectionString;
reportsTableAdapter = new SqlDataAdapter("Select * from ReportLayout", new SqlConnection(connectionString));
SqlCommandBuilder builder = new SqlCommandBuilder(reportsTableAdapter);
reportsTableAdapter.InsertCommand = builder.GetInsertCommand();
reportsTableAdapter.UpdateCommand = builder.GetUpdateCommand();
reportsTableAdapter.DeleteCommand = builder.GetDeleteCommand();
reportsTableAdapter.Fill(reportsTable);
DataColumn[] keyColumns = new DataColumn[1];
keyColumns[0] = reportsTable.Columns[0];
reportsTable.PrimaryKey = keyColumns;
if (!IsPostBack) {
reportsList.DataSource = reportsTable;
reportsList.DataMember = "Reports";
reportsList.DataTextField = "DisplayName";
reportsList.DataValueField = "ReportId";
this.DataBind();
}
}
protected void NewReportButton_Click(object sender, EventArgs e) {
Session["DesignerTask"] = new DesignerTask {
mode = ReportEdditingMode.NewReport,
};
Response.Redirect("Designer.aspx");
}
protected void EditButton_Click(object sender, EventArgs e) {
ListItem selected = reportsList.SelectedItem;
if(selected != null) {
Session["DesignerTask"] = new DesignerTask {
mode = ReportEdditingMode.ModifyReport,
reportID = selected.Value
};
Session["ReportID"] = selected.Value;
Response.Redirect("Designer.aspx");
}
}
protected void DeleteButton_Click(object sender, EventArgs e) {
ListItem selected = reportsList.SelectedItem;
if (selected != null)
{
DataRow row = reportsTable.Rows.Find(int.Parse(selected.Value));
if (row != null)
{
row.Delete();
reportsTableAdapter.Update(reportsTable);
reportsTable.AcceptChanges();
}
reportsList.Items.Remove(reportsList.SelectedItem);
}
}
}
}
ASPx<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Designer.aspx.cs" Inherits="SimpleWebReportCatalog.Designer" %>
<%@ Register Assembly="DevExpress.XtraReports.v24.2.Web.WebForms, Version=24.2.3.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"
Namespace="DevExpress.XtraReports.Web" TagPrefix="dx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<link rel="stylesheet" href="Styles/DesignerStyle.css" />
<script type="text/javascript">
// The CustomizeMenuActions event handler.
function CustomizeMenuActions(s, e) {
var actions = e.Actions;
// Register the custom Close menu command.
actions.push({
text: "Close",
imageClassName: "customButton",
disabled: ko.observable(false),
visible: true,
// The clickAction function recieves the client-side report model
// and allows you to interact with the opened report.
clickAction: function (report) {
window.location = "Default.aspx";
},
container: "menu"
});
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<dx:ASPxReportDesigner ID="ASPxReportDesigner1" runat="server" ClientSideEvents-CustomizeMenuActions="CustomizeMenuActions">
</dx:ASPxReportDesigner>
</div>
</form>
</body>
</html>
C#using System;
using DevExpress.DataAccess.Sql;
namespace SimpleWebReportCatalog {
public partial class Designer : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
DesignerTask task = (DesignerTask)Session["DesignerTask"];
if(task != null) {
InitDesignerPage(task);
}
else if(!Page.IsCallback) {
Response.Redirect("Default.aspx");
}
}
private void InitDesignerPage(DesignerTask task) {
BindToData();
switch(task.mode) {
case ReportEdditingMode.NewReport:
// Create a new report from the template.
ASPxReportDesigner1.OpenReport(new ReportTemplate());
break;
case ReportEdditingMode.ModifyReport:
// Load a report from the report storage.
ASPxReportDesigner1.OpenReport(task.reportID);
break;
}
}
private void BindToData() {
SqlDataSource ds = new SqlDataSource("Northwind");
CustomSqlQuery query = new CustomSqlQuery();
query.Name = "Products";
query.Sql = "SELECT * FROM Products";
ds.Queries.Add(query);
ds.RebuildResultSchema();
ASPxReportDesigner1.DataSources.Add("Northwind", ds);
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
namespace SimpleWebReportCatalog {
public class Global : System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.EnableCustomSql();
DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension.RegisterExtensionGlobal(new CustomReportStorageWebExtension());
DevExpress.XtraReports.Web.ASPxReportDesigner.StaticInitialize();
}
protected void Session_Start(object sender, EventArgs e) {
}
protected void Application_BeginRequest(object sender, EventArgs e) {
}
protected void Application_AuthenticateRequest(object sender, EventArgs e) {
}
protected void Application_Error(object sender, EventArgs e) {
}
protected void Session_End(object sender, EventArgs e) {
}
protected void Application_End(object sender, EventArgs e) {
}
}
}