Generate a PDF from an ASP.NET Web Page using the iTextSharp XMLWorker Namespace

If you need to quickly and easily generate PDF documents from ASP.NET, then the iTextSharp library for .NET is very convenient. To install and start using iTextSharp, you can download the zipped reference files from the SourceForge Web site and then add them to your Visual Studio project the same way as you would do with any other third party library file.

The latest version of iTextSharp has deprecated the older HTMLWorker object in favor of the newer XMLWorkerHelper object. This is good news for any developer who likes to use CSS formatting. Although the CSS support is still basic, it is a definite step up from the earlier version of the object which did not support CSS at all. For example, the new object allows a number of important behaviors such as PDF page breaks that were impossible to do using the older object.

To make use of the XMLWorkerHelper object you will need to reference two DLL files in your Visual Studio project. These are:

  1. itextsharp.dll
  2. itextsharp.xmlworker.dll

Once you have referenced these two libraries you are ready to start coding.

In this article I provide a fully working example in both C# and VB.NET. Each example consists of a report page that outputs a simple table, and the main PDF generation page. See the explanation below for further details.

Just to note: if you are interested in further information about iTextSharp then please have a look at the collection of articles I’ve written that cover using iTextSharp for .NET PDF generation.

Starting your Reports

In this article I will show how to take a report Web page written in ASP.NET and save this to the Web server as a PDF file that the user can be redirected to. This is basic functionality, but definitely useful! If you don’t want to keep a physical copy on your Server, you can simply update the code to remove the line to save the file, and then stream the document directly to the user.

Keep in mind when writing your Web report that you can use CSS, but make sure to test your report to make sure your formatting has translated correctly.

For this example you will need two Web pages.

  1. The first is your Web report that you want to export to PDF.
  2. The second is a Web page from which your users can click a button in order to generate the PDF from your Web report.

In the example code that I am providing at the end of this article, the test Web report is simply a HashTable that is databound to a GridView. For clarity, I have named the test report TestReport.aspx or CSharpTestReport.aspx for the C# version.

The page that reads the report page and converts it into a PDF file on the server is called TestGenPDF.aspx or CSharpTestGenPDF.aspx for the C# version. All of the actual iTextSharp code is written on this page.

Reviewing the iTextSharp Code

To begin working with the iTextSharp tool, you will need to import the library files from your newly referenced iTextSharp DLLs. For a basic Web page to PDF conversion you will need the following namespaces:

  • iTextSharp.tool.xml
  • iTextSharp.text.pdf
  • System.IO

For starters, you will need to include the System.IO library in order to manipulate the files on your Web server’s file system. This includes actually creating and writing the new PDF report file to a sub-folder of your Web site called Reports.

The following line tells .NET to run the Web plage and to store the resulting page inside of a StringWriter object:

 Server.Execute("TestReport.aspx", strWriter)

The iTextSharp.tool.xml library is required in order to use the XMLWorkerHelper object. In the example code below this is necessary for the following line to run correctly:

XMLWorkerHelper.GetInstance().ParseXHtml(pdfWrite, docWorkingDocument, srdDocToString)

Furthermore, the iTextSharp.text.pdf library is needed for the calls to the iTextSharp PdfWriter object which receives the stream of text that needs to be written out in PDF format in the following lines:

 Dim pdfWrite As PdfWriter
 pdfWrite = PdfWriter.GetInstance(docWorkingDocument, New FileStream(strFileName, FileMode.Create))

The sample code also makes use of the iTextSharp Document object. You can either import this separately, or in the case of the sample code below I simply referenced it directly in code to avoid any sort of confusion about what sort of document is being generated.

Dim docWorkingDocument As iTextSharp.text.Document = New iTextSharp.text.Document(iTextSharp.text.PageSize.A4.Rotate(), 1, 1, 0, 0)

As you can see, when instantiating the iTextSharp document you are also able to set various properties of the document. This includes the layout of the report in the PDF document as well as the PDF document margins.

From the line of code above you can see that I have set the example document that we are working with to generate in landscape layout.

Once this page has run the report page and output the PDF file to the Web server, it uses JavaScript to point the user’s browser to the newly generated file as follows:

Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "myscript", "window.open('reports/" & strFileShortName & "','_blank','location=0,menubar=0,status=0,titlebar=0,toolbar=0');", True)

The reason for using JavaScript instead of a simple Server Redirect is that I wish the PDF to appear in a new browser window rather than replacing the main browser window. This is a handy trick to use since opening a new window is not possible using a Server redirect.

An alternate method would be to stream the PDF directly to the user’s browser, but this can have problems as well. For example when streaming the PDF, if any extra Bytes are somehow included, Adobe will attempt to correct the PDF, and then the user will be prompted to save the streamed PDF if they click the close button.

Summary

Below I’m providing a fully working example of the iTextSharp functionality I described in this article. I provide a C# and a VB.NET version of the example.

This working example in either language consists of two pages TestGenPdf.aspx and TestReport.aspx. TestReport.aspx generates an example report as an HTML table based on a GridView control. The iTextSharp PDF functionality is contained in the TestGenPdf.aspx example page.

If you are interested in related articles, I have posted an article reviewing some of the features of the iTextSharp HTMLWorker object.

As always, please feel free to post any questions or comments related to this article in the comments section at the end of this post.

THE EXAMPLE IN C#

Here is the example written in C#. Note that as explained earlier, CSharpTestGenPdf.aspx is the main page that will run and export to PDF the report coded on the second page called CSharpTestReport.aspx.

CSharpTestGenPdf.aspx

This is the main PDF generation page that calls the report page (called CSharpTestReport.aspx). Note that I also added a line to import a logo image from an Images folder to this example. You can leave this line out if you don’t want to add an image.


<%@ Page Language="C#" %>
<%@ Import Namespace="iTextSharp.tool.xml" %>
<%@ Import Namespace="iTextSharp.text.pdf" %>
<%@ Import Namespace="System.IO" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
 protected void Button1_Click(object sender, System.EventArgs e)
 {
 string strHtml = null;
 MemoryStream memStream = new MemoryStream();
 StringWriter strWriter = new StringWriter();
 Server.Execute("CSharpTestReport.aspx", strWriter);
 strHtml = strWriter.ToString();
 strWriter.Close();
 strWriter.Dispose();
 iTextSharp.text.Image addLogo = default(iTextSharp.text.Image);
 addLogo = iTextSharp.text.Image.GetInstance(Server.MapPath("Images") + "/mylogo.gif");
 string strFileShortName = "test" + DateTime.Now.Ticks + ".pdf";
 string strFileName = HttpContext.Current.Server.MapPath("reports\\" + strFileShortName);
 iTextSharp.text.Document docWorkingDocument = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4.Rotate(), 1, 1, 0, 0);
 StringReader srdDocToString = null;
 try
 {
 PdfWriter pdfWrite = default(PdfWriter);
 pdfWrite = PdfWriter.GetInstance(docWorkingDocument, new FileStream(strFileName, FileMode.Create));
 srdDocToString = new StringReader(strHtml);
 docWorkingDocument.Open();
 addLogo.ScaleToFit(128, 37);
 addLogo.Alignment = iTextSharp.text.Image.ALIGN_RIGHT;
 docWorkingDocument.Add(addLogo);
 XMLWorkerHelper.GetInstance().ParseXHtml(pdfWrite, docWorkingDocument, srdDocToString);
 }
 catch (Exception ex)
 {
 Response.Write(ex.Message);
 }
 finally
 {
 if ((docWorkingDocument != null))
 {
 docWorkingDocument.Close();
 docWorkingDocument.Dispose();
 }
 if ((srdDocToString != null))
 {
 srdDocToString.Close();
 srdDocToString.Dispose();
 }
 }
 Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "myscript", "window.open('reports/" + strFileShortName + "','_blank','location=0,menubar=0,status=0,titlebar=0,toolbar=0');", true);
 }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <title></title>
</head>
<body>
 <form id="form1" runat="server">
 <div>
 <asp:Button ID="Button1" runat="server" Text="Generate PDF" OnClick="Button1_Click" />
 </div>
 </form>
</body>
</html>

CSharpTestReport.aspx

This is the report page that outputs a simple GridView control in table format.


<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
 Hashtable m_testData = new Hashtable();
 protected void Page_Load(object sender, System.EventArgs e)
 {
 m_testData.Add("test_1_id", "test_1_value");
 m_testData.Add("test_2_id", "test_2_value");
 m_testData.Add("test_3_id", "test_3_value");
 m_testData.Add("test_4_id", "test_4_value");
 GridView1.DataSource = m_testData;
 GridView1.DataBind();
 }
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <title></title>
</head>
<body>
 <form id="form1" runat="server">
 <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
 <Columns>
 <asp:TemplateField HeaderText="key">
 <EditItemTemplate>
 <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("key") %>'></asp:TextBox>
 </EditItemTemplate>
 <ItemTemplate>
 <asp:Label ID="Label1" runat="server" Text='<%# Bind("key") %>'></asp:Label>
 </ItemTemplate>
 </asp:TemplateField>
 <asp:TemplateField HeaderText="value">
 <EditItemTemplate>
 <asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("value") %>'></asp:TextBox>
 </EditItemTemplate>
 <ItemTemplate>
 <asp:Label ID="Label2" runat="server" Text='<%# Bind("value") %>'></asp:Label>
 </ItemTemplate>
 </asp:TemplateField>
 </Columns>
</asp:GridView>
 </form>
</body>
</html>

THE EXAMPLE IN VB.NET

Here is the exact same example written in VB.NET. Unlike the C# example above, I do not import a logo image into the PDF.

TestGenPdf.aspx

This is the main PDF generation page that calls the report page (called TestReport.aspx).

<%@ Page Language="VB" %>
<%@ Import Namespace="iTextSharp.tool.xml" %>
<%@ Import Namespace="iTextSharp.text.pdf" %>
<%@ Import Namespace="System.IO" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
 Protected Sub Button1_Click(sender As Object, e As System.EventArgs)
 Dim strHtml As String
 Dim memStream As New MemoryStream()
 Dim strWriter As New StringWriter()
 Server.Execute("TestReport.aspx", strWriter)
 strHtml = strWriter.ToString()
 strWriter.Close()
 strWriter.Dispose()
 Dim strFileShortName As String = "test" & DateTime.Now.Ticks & ".pdf"
 Dim strFileName As String = HttpContext.Current.Server.MapPath("reports\" & strFileShortName)
 Dim docWorkingDocument As iTextSharp.text.Document = New iTextSharp.text.Document(iTextSharp.text.PageSize.A4.Rotate(), 1, 1, 0, 0)
 Dim srdDocToString As StringReader = Nothing
 Try
 Dim pdfWrite As PdfWriter
 pdfWrite = PdfWriter.GetInstance(docWorkingDocument, New FileStream(strFileName, FileMode.Create))
 srdDocToString = New StringReader(strHtml)
 docWorkingDocument.Open()
 XMLWorkerHelper.GetInstance().ParseXHtml(pdfWrite, docWorkingDocument, srdDocToString)
 Catch ex As Exception
 Response.Write(ex.Message)
 Finally
 If Not docWorkingDocument Is Nothing Then
 docWorkingDocument.Close()
 docWorkingDocument.Dispose()
 End If
 If Not srdDocToString Is Nothing Then
 srdDocToString.Close()
 srdDocToString.Dispose()
 End If
 End Try

 Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "myscript", "window.open('reports/" & strFileShortName & "','_blank','location=0,menubar=0,status=0,titlebar=0,toolbar=0');", True)

 End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <title></title>
</head>
<body>
 <form id="form1" runat="server">
 <div>
 <asp:Button ID="Button1" runat="server" Text="Generate PDF" OnClick="Button1_Click" />
 </div>
 </form>
</body>
</html>

TestReport.aspx

This is the report page that outputs a simple GridView control.

</pre>
<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
 Dim m_testData As New Hashtable()
 Protected Sub Page_Load(sender As Object, e As System.EventArgs)
 m_testData.Add("test_1_id", "test_1_value")
 m_testData.Add("test_2_id", "test_2_value")
 m_testData.Add("test_3_id", "test_3_value")
 m_testData.Add("test_4_id", "test_4_value")
 GridView1.DataSource = m_testData
 GridView1.DataBind()
 End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
 <Columns>
 <asp:TemplateField HeaderText="key">
 <EditItemTemplate>
 <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("key") %>'></asp:TextBox>
 </EditItemTemplate>
 <ItemTemplate>
 <asp:Label ID="Label1" runat="server" Text='<%# Bind("key") %>'></asp:Label>
 </ItemTemplate>
 </asp:TemplateField>
 <asp:TemplateField HeaderText="value">
 <EditItemTemplate>
 <asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("value") %>'></asp:TextBox>
 </EditItemTemplate>
 <ItemTemplate>
 <asp:Label ID="Label2" runat="server" Text='<%# Bind("value") %>'></asp:Label>
 </ItemTemplate>
 </asp:TemplateField>
 </Columns>
</asp:GridView>
</form>
</body>
</html>

About these ads

5 thoughts on “Generate a PDF from an ASP.NET Web Page using the iTextSharp XMLWorker Namespace

  1. Pingback: Generate a PDF from an ASP.NET Web Page using the iTextSharp XMLWorker Namespace | Web App Dev | Scoop.it

  2. Pingback: Points to keep in mind when working with the iTextSharp HTML to PDF converter (HTMLWorker) « Justin Cooney – Programming Tips

  3. Hi, Justin
    Great article. I’m working just in the same task, but I’ve a problem with the parseXHtml method,
    i call the method this way:

    ‘ sr is an html string

    Dim document As New Document(iTextSharp.text.PageSize.A4, 1, 1, 0, 0)
    Dim writer As PdfWriter
    writer = PdfWriter.getInstance(document, New System.IO.FileStream(Request.MapPath(“\”)+”Test.pdf”, System.IO.FileMode.Create))
    document.Open()
    Dim sr2 As new System.IO.StringReader(sr)

    XMLWorkerHelper.getInstance().parseXHtml(writer, document, sr2)

    and compilation says:

    BC30311: Value of type ‘iTextSharp.text.Document’ cannot be converted to ‘System.IO.Stream’

    I’ve revied everything and I can’t find the solution,
    i check the dll versions

    itextsharp.dll 5.3.5.0
    itextsharp.xmlworker.dll 5.4.2.0

    it seems like i’m using a java version (or something similar) instead the xmlworker version you’re using
    but i can’t find a different version

    Thanks in advance and great work

    Kiko Fdez
    Spain

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s