Introduction
This article explains how to zip a folder from ASP.NET, and how a client can download and save the zipped folder locally.
Background
A few months back, in my ASP.NET application, I needed to create a handful of different reports using Crystal Reports and send those reports to the client in PDF format. If I had only one report to display, I could display it in the browser and the client could save it locally. But, the number of reports was quiet large, and I decided to put all the reports generated in a folder created dynamically, zip thes folder, and send the zipped folder to the client. Here, I will explain how I implemented all these steps. Since your overall requirement may be different, I am not giving the complete source code for this.
I have written all the code in VB.NET, using the Visual Studio 2005 IDE, and you can easily convert it to C#.
Generating Crystal Reports in PDF format and displaying it in the browser
Generating Crystal Reports in PDF Format
This code snippet explains how to generate a Crystal Reports report in PDF format and show it in the client browser. I assume you have already created (designed) a report using Crystal Reports.
This function will create the report in PDF format and sent it to the caller as a memory stream:
Public Function CreatePDFStream() As MemoryStream
Dim newConnectionInfo As ConnectionInfo = GetConnectionInfo()
Dim report As New ReportDocument
Dim reportPath As String = Server.MapPath(".\Reports\Myreport.rpt")
Dim PDFStream As MemoryStream
report.Load(reportPath, OpenReportMethod.OpenReportByTempCopy)
SetDBLogonForReport(newConnectionInfo, report)
SetCurrentValuesForParameterField(report)
With report
.ExportOptions.ExportDestinationType = _
CrystalDecisions.Shared.ExportDestinationType.DiskFile
.ExportOptions.ExportFormatType = _
CrystalDecisions.Shared.ExportFormatType.PortableDocFormat
.Refresh()
SetCurrentValuesForParameterField(report)
PDFStream = CType(.ExportToStream(ExportFormatType.PortableDocFormat), _
MemoryStream)
.Close()
End With
Return PDFStream
End Function
In the above function, GetConnectionInfo
will simply read the connection details from the config file and store the details in a CrystalDecisions.Shared.ConnectionInfo
. This ConnectionInfo
is later used by the report to get connected to the server. It is done in the function SetDBLogonForReport
, and the same is reproduced bewlow.
ConnectionInfo
needs the following properties to be set, and the code is given below:
With newConnectionInfo
DatabaseName = conn.Database
ServerName = conn.Server
UserID = conn.User
.Password = conn.Password
End With
SetDBLogOnForReport
will set the connection and databsae properties for the report, and here is the code:
Private Sub SetDBLogonForReport(ByVal connectionInfo As ConnectionInfo, _
ByVal myReportDocument As ReportDocument)
Dim crtableLogoninfos As New TableLogOnInfos()
Dim crtableLogoninfo As New TableLogOnInfo()
Dim crConnectionInfo As New ConnectionInfo()
Dim crTables As Tables
Dim crTable As Table
crTables = myReportDocument.Database.Tables
For Each crTable In crTables
crtableLogoninfo = crTable.LogOnInfo
crtableLogoninfo.ConnectionInfo = connectionInfo
crTable.ApplyLogOnInfo(crtableLogoninfo)
crTable.Location = connectionInfo.DatabaseName & ".dbo." & _
crTable.Location.Substring(crTable.Location.LastIndexOf(".") + 1)
crTable.LogOnInfo.ConnectionInfo.ServerName = connectionInfo.ServerName()
Next
End Sub
After setting the connection details, we need to set the parameters (if any) for the report. In my case, I will get the required parameters from the query string. SetCurrentValuesForParameterField
will do the job.
Private Sub SetCurrentValuesForParameterField(ByVal myReportDocument As ReportDocument)
ProcessQueryString()
Dim currentFirstParameteValues As ParameterValues = New ParameterValues()
Dim currentSecondParameterValues As ParameterValues = New ParameterValues()
Dim FirstParameterValue As New CrystalDecisions.Shared.ParameterDiscreteValue
Dim SecondParameterValue As New CrystalDecisions.Shared.ParameterDiscreteValue
FristParameterValue.Value = xxxxx
SecondParameterValue.Value = yyyy
currentFirstParameterValues.Add(FirstParameterValue)
currentSecondParameterValues.Add(SecondParameterValue)
Dim SSTParameterFieldDefinitions As ParameterFieldDefinitions = _
myReportDocument.DataDefinition.ParameterFields
Dim FirstParameterFieldDefinition As ParameterFieldDefinition = _
SSTParameterFieldDefinitions(0)
Dim SecondParameterFieldDefinition As ParameterFieldDefinition = _
SSTParameterFieldDefinitions(1)
FristParameterFieldDefinition.ApplyCurrentValues(currentFirstParameterValues)
SecondParameterFieldDefinition.ApplyCurrentValues(currentSecondParameterValues)
End Sub
Showing the PDF report in the browser
Showing the PDF report in browser is really simple:
PDFStream= CreatePDFStream
If Not PDFStream is nothing Then
Response.Clear()
Response.Buffer = True
Response.ContentType = "application/pdf"
Response.BinaryWrite(PDFStream.ToArray())
Response.End()
PDFStream.Close()
End If
Zipping a folder
Before explaining how to zip a folder, let me explain how to direct the zipped folder to the browser so that the client can download and save it. This code assumes you know the path to the zipped folder.
zippedFolderPath = zippath
Me.Response.Clear()
Me.Response.AddHeader("Content-Disposition", _
"attachment; filename=" + _
zippedFolderPath)
Me.Response.ContentType = "Application/X-zip-compressed"
Me.Response.WriteFile(zippedFolderPath)
Me.Response.Flush()
System.IO.File.Delete(zippedFolderPath)
In order to zip a folder, you need to add a few namespaces. All these namespaces are part of the Visual J# library, vjslib.dll. So first, you need to add this library to the application. You can find this library in the .NET framework version path. In my machine, it is available in C:\Windows\Microsoft.Net\FrameWork\V2.0.50727\vjslib.dll.
The namespaces to be imported are:
Imports java.io
Imports java.util
Imports java.util.zip
The following function will create individual PDF reports, put them in a newly created folder, zip the folder, and return the name of zipped file to the caller:
Private Function CreatePDFFiles() As String
Dim outPutDirectoryName As String
outPutDirectoryName = _outputPath + "_" + _sessionID
createOutputDirectory(outPutDirectoryName) ‘ Create a directory
Dim zipFileName As String = outPutDirectoryName & ".zip"
Dim PDFStream As MemoryStream
For Each kvp As KeyValuePair(Of Integer, String) In details
PDFStream = CreatePDFStream() ‘already explained
Dim pdfBuffer(CType(PDFStream.Length - 1, Integer)) As Byte
PDFStream.Read(pdfBuffer, 0, pdfBuffer.Length)
PDFStream.Close()
Dim PDFFileName As String
PDFFileName = outPutDirectoryName + "\" + CreateOutPutPDFFileName(code)
Dim PDFFile As New FileStream(PDFFileName, _
FileMode.Create, FileAccess.Write)
PDFFile.Write(pdfBuffer, 0, pdfBuffer.Length)
PDFFile.Close()
Next
'Zipping folder
If System.IO.Directory.Exists(outPutDirectoryName) Then
Dim fos As java.io.FileOutputStream
Dim zos As java.util.zip.ZipOutputStream
Dim di As System.IO.DirectoryInfo
'create a zip file with same name in the same path
If System.IO.File.Exists(zipFileName) Then
System.IO.File.Delete(zipFileName)
End If
fos = New java.io.FileOutputStream(zipFileName)
zos = New java.util.zip.ZipOutputStream(fos)
di = New System.IO.DirectoryInfo(outPutDirectoryName)
'procedure to zip a directory
ZipFolder(fos, zos, di, outPutDirectoryName)
zos.close()
fos.close()
zos.flush()
fos.flush()
End If
DeleteOutputDirectory(outPutDirectoryName)
Return zipFileName.Substring(zipFileName.LastIndexOf("\") + 1)
End Function
The ZipFolder
procedure will do the zipping:
Private Sub ZipFolder(ByVal fileOutputStream As java.io.FileOutputStream _
, ByVal zipOutputStream As java.util.zip.ZipOutputStream _
, ByVal directoryInfo As System.IO.DirectoryInfo _
, ByVal SRootDir As String)
Dim fileInputStream As java.io.FileInputStream
Dim zipEntry As java.util.zip.ZipEntry
Dim PDFReportInfos As System.IO.FileInfo() = directoryInfo.GetFiles
Dim PDFReportInfo As System.IO.FileInfo
For Each PDFReportInfo In PDFReportInfos
zipEntry = New java.util.zip.ZipEntry(_
PDFReportInfo.FullName.Substring(SRootDir.LastIndexOf("\")))
zipEntry.setMethod(zipEntry.DEFLATED)
zipOutputStream.putNextEntry(zipEntry)
fileInputStream = New java.io.FileInputStream(PDFReportInfo.FullName)
Dim reader As New java.io.InputStreamReader(fileInputStream)
Dim writer As New java.io.OutputStreamWriter(zipOutputStream)
While reader.ready
writer.write(reader.read)
End While
writer.flush()
zipOutputStream.closeEntry()
fileInputStream.close()
Next
End Sub
Conclusion
This article only gives you an outline of how to do things, since the complete code is out of the scope.