In this article I will explain with an example, how to solve the problem of Print and Export Button of Toolbar not working with Crystal Report Viewer in SAP Crystal Reports in ASP.Net.
The Problem
Crystal Report Viewer Control has option to Export Crystal Reports to different formats PDF, Excel File (XLS) and CSV.
Once you click the Export Button a dialog appears which allow you to select the format you want to export the report.
Once you click Export button you will get the following error message that stuns you.
The Cause
After investigating I managed to get to the root of the issue. Actually I placed a break point in the Page_Load event and found that the Crystal Report Viewer Control’s Export Button does a PostBack and if your code to bind the Crystal Report is written in Not IsPostBack condition then the Crystal Report is not set with a DataSource, thus leaving it empty with no data.
In simple words Crystal Report and Crystal Report Viewer Control both must be provided with DataSource and ReportSource respectively always whenever a call to server is made.
The Solution
I have two solutions you can go with whichever one as per your application design.
Solution 1: Move Crystal Report binding code out of Not IsPostBack condition
Move Crystal Report binding code out of Not IsPostBack condition so that Crystal Report and Crystal Report Viewer Control both are provided with DataSource and ReportSource respectively always.
C#
protected void Page_Load(object sender, EventArgs e)
{
ReportDocument crystalReport = new ReportDocument();
crystalReport.Load(Server.MapPath("~/CustomerReport.rpt"));
Customers dsCustomers = GetData("select * from customers");
crystalReport.SetDataSource(dsCustomers);
CrystalReportViewer1.ReportSource = crystalReport;
}
private Customers GetData(string query)
{
string conString = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
SqlCommand cmd = new SqlCommand(query);
using (SqlConnection con = new SqlConnection(conString))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
using (Customers dsCustomers = new Customers())
{
sda.Fill(dsCustomers, "DataTable1");
return dsCustomers;
}
}
}
}
VB.Net
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim crystalReport As New ReportDocument()
crystalReport.Load(Server.MapPath("~/CustomerReport.rpt"))
Dim dsCustomers As Customers = GetData("select * from customers")
crystalReport.SetDataSource(dsCustomers)
CrystalReportViewer1.ReportSource = crystalReport
End Sub
Private Function GetData(query As String) As Customers
Dim conString As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
Dim cmd As New SqlCommand(query)
Using con As New SqlConnection(conString)
Using sda As New SqlDataAdapter()
cmd.Connection = con
sda.SelectCommand = cmd
Using dsCustomers As New Customers()
sda.Fill(dsCustomers, "DataTable1")
Return dsCustomers
End Using
End Using
End Using
End Function
Solution 2: Preserve Data using ViewState or Session during PostBack
The solution #2 makes use of ViewState variable to preserve the data fetched across PostBack so that there is no need to make calls to the database always.
The Customer records are fetched only once when the page loads for the first time into a DataSet which is then stored into the ViewState variable.
C#
protected void Page_Load(object sender, EventArgs e)
{
Customers dsCustomers = null;
if (!IsPostBack)
{
dsCustomers = GetData("select * from customers");
ViewState["Customers_Data"] = dsCustomers;
}
ReportDocument crystalReport = new ReportDocument();
crystalReport.Load(Server.MapPath("~/CustomerReport.rpt"));
dsCustomers = (Customers)ViewState["Customers_Data"];
CrystalReportViewer1.ReportSource = crystalReport;
crystalReport.SetDataSource(dsCustomers);
}
private Customers GetData(string query)
{
string conString = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
SqlCommand cmd = new SqlCommand(query);
using (SqlConnection con = new SqlConnection(conString))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
using (Customers dsCustomers = new Customers())
{
sda.Fill(dsCustomers, "DataTable1");
return dsCustomers;
}
}
}
}
VB.Net
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim dsCustomers As Customers = Nothing
If Not IsPostBack Then
dsCustomers = GetData("select * from customers")
ViewState("Customers_Data") = dsCustomers
End If
Dim crystalReport As New ReportDocument()
crystalReport.Load(Server.MapPath("~/CustomerReport.rpt"))
dsCustomers = DirectCast(ViewState("Customers_Data"), Customers)
CrystalReportViewer1.ReportSource = crystalReport
crystalReport.SetDataSource(dsCustomers)
End Sub
Private Function GetData(query As String) As Customers
Dim conString As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
Dim cmd As New SqlCommand(query)
Using con As New SqlConnection(conString)
Using sda As New SqlDataAdapter()
cmd.Connection = con
sda.SelectCommand = cmd
Using dsCustomers As New Customers()
sda.Fill(dsCustomers, "DataTable1")
Return dsCustomers
End Using
End Using
End Using
End Function
Screenshot
Demo
Downloads