Introduction
Every one knows the problems which one faces while working with Crystal Reports due to its poor and confusing documentation. I am presenting here a ready to go code to access reports developed in Crystal Reports 9 (with or without RAS 9) using ASP.NET. This article consists of two parts: first part presents the code if the reports are placed under a RAS server, while the second part shows how to do the same job if the reports are kept without any RAS server.
1. Showing Crystal Reports from RAS 9 in PDF format using ASP.NET
This is the code which presents how to show Crystal Reports placed under a RAS 9 server using ASP.NET. The final report will be shown in PDF format. You can change the output format. I have clearly marked the place in the code where you can make modifications to change the output format of the report.
Setup
Just put the following parameters in the appsettings
of your web.confog file:
ServerName
- machine on which your SQL Server resides, e.g.: machine_sqlsvr2000_1.
DatabaseName
- database name on your SQL Server, e.g.: northwind.
RASServer
- name of the server which has the reports, e.g., machine_reportserver_9_1.
ReportPath
- path on the RAS server where the reports are kept, e.g., c:\proects\project1\reports\.
UserID
and Password
- user name and password for your database.
Then, you need to put this method on the ASP.NET page which will be used to call the reports.
Public Sub CreateReport()
Dim m_RptName As String = "report1.rpt"
Dim _db_server As String = ConfigurationSettings.AppSettings("ServerName")
Dim _db_name As String = ConfigurationSettings.AppSettings("DatabaseName")
Dim _ras_server As String = ConfigurationSettings.AppSettings("RASServer")
Dim _file_name As String = _
ConfigurationSettings.AppSettings("ReportPath") & m_RptName
Dim _user_id As String = ConfigurationSettings.AppSettings("UserID")
Dim _pwd As String = ConfigurationSettings.AppSettings("Password")
Dim oRptViewer As New RASReportViewer
Dim rcDoc As ReportClientDocument
rcDoc = New ReportClientDocument
rcDoc.ReportAppServer = _ras_server
rcDoc.Open(_file_name)
oRptViewer.Logon(rcDoc, _user_id, _pwd, _db_server, _db_name)
oRptViewer.PassParameter(rcDoc, "", 0, Session("CategoryString"))
oRptViewer.PassParameter(rcDoc, "", 1, Session("Terms"))
oRptViewer.PassParameter(rcDoc, "", 2, Session("Division"))
oRptViewer.PassParameter(rcDoc, "", 3, Session("Location"))
Dim byteArray As ByteArray = _
rcDoc.PrintOutputController.Export(_
CrReportExportFormatEnum.crReportExportFormatPDF)
Response.ClearContent()
Response.ClearHeaders()
Response.ContentType = "application/pdf"
Response.BinaryWrite(byteArray.DetachArray)
Response.Flush()
Response.Close()
oRptViewer.Dispose()
If Not oRptViewer Is Nothing Then
oRptViewer = Nothing
End If
End Sub
You can make changes in the above method if you want to show your reports in some format other than PDF. You will have to change the following lines only:
Response.ClearContent()
Response.ClearHeaders()
Response.ContentType = "application/pdf"
Response.BinaryWrite(byteArray.DetachArray)
Response.Flush()
RASReportViewer Class
Here is the class that the above method is using. You can just use it as it is. I think you will not need to make any modifications at all in this class. I have developed it as a component class. If you want, you can change it into a simple class too.
Imports CrystalDecisions.ReportAppServer.ClientDoc
Imports CrystalDecisions.ReportAppServer.Controllers
Imports CrystalDecisions.ReportAppServer.DataDefModel
Imports CrystalDecisions.ReportAppServer.CommonObjectModel
Public Class RASReportViewer
Inherits System.ComponentModel.Component
Dim rcDoc As ReportClientDocument
Dim m_last_error As String
#Region " Component Designer generated code "
Public Sub New(ByVal Container As System.ComponentModel.IContainer)
MyClass.New()
Container.Add(Me)
End Sub
Public Sub New()
MyBase.New()
InitializeComponent()
End Sub
Public Sub PassParameter( _
ByRef doc As ReportClientDocument, _
ByVal report_name As String, _
ByVal param_name As String, _
ByVal param_value As Object)
Dim param_val As New ParameterFieldDiscreteValue
param_val.Value = param_value
Dim vals As New Values
vals.Add(param_val)
doc.DataDefController.ParameterFieldController._
SetCurrentValues(report_name, param_name, vals)
End Sub
Public Sub PassParameter( _
ByVal doc As ReportClientDocument, _
ByVal report_name As String, _
ByVal param_index As Integer, _
ByVal param_value As Object)
PassParameter(doc, report_name, _
doc.DataDefinition.ParameterFields(param_index).Name, _
param_value)
End Sub
Private Function ApplyLogon( _
ByVal doc As ReportClientDocument, _
ByVal database As Database, _
ByVal ci As ConnectionInfo, _
ByVal report_name As String) As Boolean
Dim table_old As _
CrystalDecisions.ReportAppServer.DataDefModel.Table
For Each table_old In database.Tables
Dim table_new As New _
CrystalDecisions.ReportAppServer.DataDefModel.Table
table_new.Name = table_old.Name
table_new.ConnectionInfo = ci
Dim qualified_name As String = table_old.QualifiedName
qualified_name = _
qualified_name.Substring(qualified_name.IndexOf("."))
qualified_name = CType(ci.Attributes("QE_LogonProperties"), _
PropertyBag)("Initial Catalog").ToString() + qualified_name
table_new.QualifiedName = qualified_name
Try
If (report_name.Length > 0) Then
doc.SubreportController.SetTableLocation(report_name,_
table_old, table_new)
Else
doc.DatabaseController.SetTableLocation(table_old,_
table_new)
End If
Catch x As Exception
m_last_error = x.Message
Return (False)
End Try
Next
Return (True)
End Function
Public Function Logon( _
ByVal doc As ReportClientDocument, _
ByVal uid As String, _
ByVal pass As String, _
ByVal server As String, _
ByVal database As String) As Boolean
Dim ci As ConnectionInfo = _
doc.DatabaseController.GetConnectionInfos(Nothing)(0).Clone(True)
ci.UserName = uid
ci.Password = pass
Dim li As PropertyBag = ci.Attributes("QE_LogonProperties")
li("Data Source") = server
li("Initial Catalog") = database
If (Not ApplyLogon(doc, doc.Database, ci, "")) Then
Return (False)
End If
Dim sub_name As String
For Each sub_name In doc.SubreportController.QuerySubreportNames()
If (Not ApplyLogon(doc, _
doc.SubreportController.GetSubreportDatabase(sub_name), _
ci, sub_name)) Then
Return (False)
End If
Next
Return (True)
End Function
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
Private components As System.ComponentModel.IContainer
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
components = New System.ComponentModel.Container
End Sub
#End Region
End Class
2. Class to show Crystal Reports 9 reports in PDF format without RAS
Most of the time, the reports are not kept on a RAS server. Instead they are just kept in another folder. In that case, you can use this class to access reports developed using Crystal Reports 9 through your ASP.NET pages. You will just have to pass the parameters to the CreateReport
method of this class and that's it. All the subsequent stuff is taken care of by this code. You will get a nice report in PDF at the end. Just like the previous class, you can modify this class too to get the report in some other format.
Setup
You just have to set up a few parameters in your web.config file which are:
ReportPath
- the path of the report that you want to show;
ServerName
, DatabaseName
, UserID
and Password
- basically your connection string.
Arguments:
sReport
- report name;
arParams
- parameters expected by the report;
DoParams
- False
if the report has no parameters.
Here is the class
Imports CrystalDecisions.CrystalReports.Engine
Imports CrystalDecisions.Shared
Imports CrystalDecisions.Web.Design
Imports System.IO
Public Class ShowCRInPDF
Public Sub CreateReport(ByVal sReport As String, ByVal _
arParams As Array, Optional ByVal _
DoParams As Boolean = True)
Dim oRpt As New ReportDocument
Dim oSubRpt As New ReportDocument
Dim Counter As Integer
Dim crSections As Sections
Dim crSection As Section
Dim crReportObjects As ReportObjects
Dim crReportObject As ReportObject
Dim crSubreportObject As SubreportObject
Dim crDatabase As Database
Dim crTables As Tables
Dim crTable As Table
Dim crLogOnInfo As TableLogOnInfo
Dim crConnInfo As New ConnectionInfo
Dim crParameterValues As ParameterValues
Dim crParameterDiscreteValue As ParameterDiscreteValue
Dim crParameterRangeValue As ParameterRangeValue
Dim crParameterFieldDefinitions As ParameterFieldDefinitions
Dim crParameterFieldDefinition As ParameterFieldDefinition
Dim crParameterFieldDefinition2 As ParameterFieldDefinition
Dim strFile As String
Dim fi As FileInfo
Dim tstr As String
Dim sPath As String
Dim configurationAppSettings As _
System.Configuration.AppSettingsReader = _
New System.Configuration.AppSettingsReader
Dim sReportPath As String = _
configurationAppSettings.GetValue("ReportPath", _
GetType(System.String)) & sReport
Dim pos As Integer
tstr = Microsoft.VisualBasic.Format(Now, "MM/dd/yyyy HH:mm:ss")
oRpt.Load(sReportPath)
crDatabase = oRpt.Database
crTables = crDatabase.Tables
For Each crTable In crTables
With crConnInfo
.ServerName = _
configurationAppSettings.GetValue("ServerName", _
GetType(System.String))
.DatabaseName = _
configurationAppSettings.GetValue("DatabaseName", _
GetType(System.String))
.UserID = _
configurationAppSettings.GetValue("UserID", _
GetType(System.String))
.Password = _
configurationAppSettings.GetValue("Password", _
GetType(System.String))
End With
crLogOnInfo = crTable.LogOnInfo
crLogOnInfo.ConnectionInfo = crConnInfo
crTable.ApplyLogOnInfo(crLogOnInfo)
Next
crSections = oRpt.ReportDefinition.Sections
For Each crSection In crSections
crReportObjects = crSection.ReportObjects
For Each crReportObject In crReportObjects
If crReportObject.Kind = ReportObjectKind.SubreportObject Then
crSubreportObject = CType(crReportObject, SubreportObject)
oSubRpt = _
crSubreportObject.OpenSubreport(_
crSubreportObject.SubreportName)
crDatabase = oSubRpt.Database
crTables = crDatabase.Tables
For Each crTable In crTables
With crConnInfo
.ServerName = _
configurationAppSettings.GetValue("ServerName", _
GetType(System.String))
.UserID = _
configurationAppSettings.GetValue("UserID", _
GetType(System.String))
.Password = _
configurationAppSettings.GetValue("Password", _
GetType(System.String))
End With
crLogOnInfo = crTable.LogOnInfo
crLogOnInfo.ConnectionInfo = crConnInfo
crTable.ApplyLogOnInfo(crLogOnInfo)
Next
End If
Next
Next
If DoParams Then
crParameterFieldDefinitions = oRpt.DataDefinition.ParameterFields()
For Counter = 0 To UBound(arParams)
crParameterFieldDefinition = _
crParameterFieldDefinitions.Item(Counter)
crParameterValues = crParameterFieldDefinition.CurrentValues
If Not IsArray(arParams(Counter)) Then
Dim test As String
Dim paramcounter As Integer
For paramcounter = 0 To UBound(arParams)
test = arParams(paramcounter)
If test.StartsWith(_
crParameterFieldDefinition.ParameterFieldName()) Then
crParameterDiscreteValue = New ParameterDiscreteValue
crParameterDiscreteValue.Value = _
test.Substring(test.IndexOf("=") + 1)
crParameterValues.Add(crParameterDiscreteValue)
Exit For
End If
Next
Else
crParameterRangeValue = New ParameterRangeValue
crParameterRangeValue.StartValue = arParams(Counter)(0)
crParameterRangeValue.EndValue = arParams(Counter)(1)
crParameterValues.Add(crParameterRangeValue)
End If
crParameterFieldDefinition.ApplyCurrentValues(crParameterValues)
Next
End If
Dim s As System.IO.MemoryStream = _
oRpt.ExportToStream(ExportFormatType.PortableDocFormat)
With HttpContext.Current.Response
.ClearContent()
.ClearHeaders()
.ContentType = "application/pdf"
.AddHeader("Content-Disposition", "inline; filename=Report.pdf")
.BinaryWrite(s.ToArray)
.End()
End With
End Sub
End Class
Reference: Crystal Reports and RAS 9.0 Documentation and Samples from www.businessobjects.com.