Nov
25

Create a PDF using the .Net ReportViewer control

posted on 25 November 2009 in programming

Warning: Please consider that this post is over 14 years old and the content may no longer be relevant.

Need to generate a pdf programmatically in dot net? You could purchase an HTML to PDF converter and worry about getting the page to format nicely for paper, or you could use the freely available ReportViewer control from Microsoft.

Microsoft offers SQL Server Reporting Services (SSRS) with SQL Server 2005 and later editions to generate and publish reports using the Report Definition Language (RDL), as an alternative to Crystal Reports. SSRS requires a Report Server to publish reports to so they can be useful, however they also offer a ASP.Net or Windows Forms component called the ReportViewer which we can use in our code without the need for any SQL database to generate reports, and these reports can be saved as Excel files, PDF’s or images.

The ReportViewer uses a modified version of RDL called RDLC, which does not save any information about the data source along with the report, which makes it perfect for generating reports from objects that aren’t a database. For instance, I recently needed to generate PDF letters with custom information in them, so this solution proved perfect.

I’m going to demonstrate how to pass parameters to an ASP.Net page and return a PDF with that information in it, this could just as easily be done in a Windows Forms project. I’m using Visual Studio 2005, in my preferred language of c#.

Start by creating a new Web Site in Visual Studio. We are going to use a collection of custom business objects as the data source for our report, so add a new class to our project and call it Person.cs. Copy the following code into your Person.cs file.

using System;
using System.Collections.Generic;

/// <summary>
/// The business object we want to use in our report.
/// </summary>
public class Person
{
    /// <summary>
    /// Some fields to hold information about this person.
    /// </summary>
    private string _title;
    private string _firstName;
    private string _lastName;

    /// <summary>
    /// The person properties are only able to be set at instantiation.
    /// After the object is created the properties are read only.
    /// </summary>
    public string Title
    {
        get { return _title; }
    }

    public string FirstName
    {
        get { return _firstName; }
    }

    public string LastName
    {
        get { return _lastName; }
    }

    /// <summary>
    /// The person constructor.
    /// </summary>
    /// <param name="title">The person's title</param>
    /// <param name="firstName">Their first name</param>
    /// <param name="lastname">Their last name</param>
    public Person(string title, string firstName, string lastname)
    {
        _title = title;
        _firstName = firstName;
        _lastName = lastname;
    }
}

/// <summary>
/// Creates a data source for our report.
/// </summary>
public class PersonDataSource
{
    /// <summary>
    /// This method creates a new person object and adds them to a new collection that
    /// can be used as a data source for the report.
    /// </summary>
    /// <returns>A collection of person objects.</returns>
    public static List<Person> GetPerson(string title, string firstName, string lastName)
    {
        List<Person> people = new List<Person>();
        people.Add(new Person(title, firstName, lastName));
        return people;
    }
}

Now that we have our business object we can create the report. Click add item on the project and select Report. Call this item Report.rdlc.

In the left hand toolbar you should see Website Data Sources (if not select Data > Show Data Sources from the file menu) and in the data sources you should see our Person object. You can now build a report using the fields from our person object and the tools in the toobox. For simplicity just drag some Textboxes onto the report from the toolbox and enter any static text in them that you want, then drag on the Person’s title, firstName and lastName and arrange them appropriately.

ReportViewer business object data source

Finally we need to write the code which will create the person data source and generate the report. Before we do this we need a reference to the ReportViewer control, right click on the project and Add Reference, in the .Net tab, select Microsoft.ReportViewer.WebForms.Now copy the following code into the Default.aspx source.

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_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>Untitled Page</title>
</head>
<body>
	<form id="form1" runat="server">
	<div>
	<asp:Label ID="lblTitle" runat="server" Text="Title: "></asp:Label>
	<asp:TextBox ID="txtTitle" runat="server">Mr</asp:TextBox>  
	<asp:Label ID="lblFirstName" runat="server" Text="First Name: "></asp:Label>
	<asp:TextBox ID="txtFirstName" runat="server">John</asp:TextBox>  
	<asp:Label ID="lblLastName" runat="server" Text="Last Name: "></asp:Label>
	<asp:TextBox ID="txtLastName" runat="server">Smith</asp:TextBox>  
	<asp:Button ID="Button1" runat="server" Text="Submit" /></div>
	</form>
</body>
</html>

And copy the following into the Code View of Default.aspx (Default.aspx.cs).

using System;
using System.Web;
using Microsoft.Reporting.WebForms;
using System.IO;
using System.Text;
using System.Collections.Generic;
public partial class _Default : System.Web.UI.Page
{
	protected void Page_Load(object sender, EventArgs e)
	{
		if (Page.IsPostBack)
		{
			LocalReport report = new LocalReport();
			string reportName = "CompletionCertificate";
			string deviceInfo =
				"<DeviceInfo>" +
				"  <OutputFormat>EMF</OutputFormat>" +
				"  <PageWidth>8.5in</PageWidth>" +
				"  <PageHeight>11in</PageHeight>" +
				"  <MarginTop>0.25in</MarginTop>" +
				"  <MarginLeft>0.25in</MarginLeft>" +
				"  <MarginRight>0.25in</MarginRight>" +
				"  <MarginBottom>0.25in</MarginBottom>" +
				"</DeviceInfo>";
			Warning[] warnings;
			string[] streamids;
			string mimeType;
			string encoding;
			string extension;

			report.ReportPath = "Report.rdlc";
			report.DataSources.Add(new ReportDataSource("Person", PersonDataSource.GetPerson(txtTitle.Text, txtFirstName.Text, txtLastName.Text)));
			byte[] bytes = report.Render("PDF", deviceInfo, out mimeType, out encoding, out extension, out streamids, out warnings);

			Response.Clear();
			Response.ContentType = mimeType;
			Response.AddHeader("Content-Disposition", "attachment; filename=" + reportName + "." + extension);
			Response.OutputStream.Write(bytes, 0, bytes.Length);
			Response.End();
		}
	}
}

Now run your project, enter some person data into the form and click submit. Open the PDF file and verify that the report is addressed to your person.

Download source