Click here to Skip to main content
15,881,898 members
Articles / Web Development / ASP.NET
Article

Creating a Proxy to Download PDF Reports from SRS

Rate me:
Please Sign up or sign in to vote.
3.40/5 (4 votes)
12 May 2008CPOL3 min read 24.1K   27   6
How to create a proxy that downloads PDF reports from SRS and then stream them back to the client browser

Introduction

The following article describes how you can create a proxy page that converts a SQL Server Report into a PDF file. When the code is executed, it will make a call to a report on a SQL Reporting Services Server, generate a PDF file and then present it to the user as an option download.

A nice benefit to this process is that you never have to save a physical file on the server and then direct the client to that file. Everything is done in memory, so there will be no file permission problems or disk space issues to deal with.

Background

While this code is useful for creating PDF copies of an SRS report, the true value is that you no longer have to grant everyone access to the reports within Reporting Services. To do this, you simply log into the Reporting Services website and set up a single user account that will have access to the reports. From there, be sure to reference this same user account in the credentials when setting up the web request.

This code can also be easily modified to download other types of files from other URLs.

Using the Code

To begin, we must first construct a URI that points to the report on the report server.

string url = "http://localhost/ReportServer/Pages/ReportViewer.aspx?%2fInvoices%2fCurrent&rs%3aCommand=Render&rs%3AFormat=PDF&InvoiceId=1";

Breakdown of the above URL:

http://localhost/ReportServer/Pages/ReportViewer.aspx
- This should point to the ReportViewer page that comes with reporting services.
Invoices
/- This is a folder that you set up in Reporting Services. If your report is in a sub folder, you will need to specify the full path separated by %2f
Current
- This is the name of your report as seen in reporting services
Command=Render
- This is required to tell the server to generate the report
Format=PDF
- This will render the output as PDF. Reporting Services can render in other formats as well
InvoiceId=1
- This is a custom parameter that gets passed into the report. In this instance, we simply pass id #1

It is possible to create a custom filename for the PDF when it gets downloaded to the client.

// this name is what the user will see when they are prompted for download.
string customFileName = "NewFileName.pdf";

This section shows how to set up user credentials to access the Report Server. I used CredentialCache.DefaultCredentials for testing on localhost. When accessing this on a remote server, you may need to pass in user credentials.

// Create a request object that will make a call to the reporting server
WebRequest request = WebRequest.Create(url);
request.ContentType = @"application/pdf";

// If you require authentication to access your report server, set the variables below
string userName = "";
string password = "";
string domain = "";

// If your server requires authentication, you will have to pass them into the request object
if (userName.Length > 0)
{
    // Create and then pass in network credentials to acecss the reporting server
    System.Net.NetworkCredential credentials = new NetworkCredential(userName, password, domain);
    request.Credentials = credentials;
}
else
    // use the default credentials
    request.Credentials = CredentialCache.DefaultCredentials;

This code captures the response from the Report Server and then saves the results into a MemoryStream object so that it can be passed back to the client. To accomplish this, we call the ReadFully method to convert the Stream into a byte array which then gets fed into the MemoryStream. Source code for this method can be found at http://www.developerfusion.co.uk/show/4696/ and is also included in the sample project.

MemoryStream ms;

// Send a request to download the pdf document and then get the response
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{

    // Get the stream from the server
    using (Stream stream = response.GetResponseStream())
    {
        // Use the ReadFully method from the link above:
        byte[] data = ReadFully(stream, response.ContentLength);

        // Return the memory stream.
        ms = new MemoryStream(data);
    }
}

The code for ReadFully can be seen below. This was originally posted at http://www.developerfusion.co.uk/show/4696/

/// Reads data from a stream until the end is reached. The
/// data is returned as a byte array. An IOException is
/// thrown if any of the underlying IO calls fail.
/// 
/// Original code can be found at http://www.developerfusion.co.uk/show/4696/
public static byte[] ReadFully(Stream stream, long initialLength)
{
    // If we've been passed an unhelpful initial length, just
    // use 32K.
    if (initialLength < 1)
    {
        initialLength = 32768;
    }

    byte[] buffer = new byte[initialLength];
    int read = 0;

    int chunk;
    while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
    {
        read += chunk;

        // If we've reached the end of our buffer, check to see if there's
        // any more information
        if (read == buffer.Length)
        {
            int nextByte = stream.ReadByte();

            // End of stream? If so, we're done
            if (nextByte == -1)
            {
                return buffer;
            }

            // Nope. Resize the buffer, put in the byte we've just
            // read, and continue
            byte[] newBuffer = new byte[buffer.Length * 2];
            Array.Copy(buffer, newBuffer, buffer.Length);
            newBuffer[read] = (byte)nextByte;
            buffer = newBuffer;
            read++;
        }
    }
    // Buffer is now too big. Shrink it.
    byte[] ret = new byte[read];
    Array.Copy(buffer, ret, read);
    return ret;
}

The final block of code clears out the current Response object and then sends it to the client for download. We also add a header to declare a custom filename from above and then set the content type to PDF so the browser knows how to handle the file. The last line of code simply sends the MemoryStream object to the browser which then prompts the user for download.

// Clear out the headers that may already exist, then set content type and add a header to name the file
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "inline; filename=" + customFileName);

// Write the memory stream containing the pdf file directly to the Response object that gets sent to the client
ms.WriteTo(Response.OutputStream);

Points of Interest

While this example shows how to download a PDF file from SRS, many more formats are available such as CSV and Excel. To use these formats, locate the Format=PDF command in the URI and change PDF to either CSV or Excel. You will also have to update the Response.ContentType accordingly.

This code uses SQL Reporting Services as an example, however it is not limited to just SRS. You can easily change the URL and alter the content types to access any type of file on the web.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Spectrum Medical
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 1 Pin
Saud AKhter9-May-14 22:14
Saud AKhter9-May-14 22:14 
QuestionThe remote server returned an error: (401) Unauthorized Pin
Farhad Navaei13-Sep-12 11:36
Farhad Navaei13-Sep-12 11:36 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey9-Feb-12 22:08
professionalManoj Kumar Choubey9-Feb-12 22:08 
Generalunathorized Pin
marlonskie103027-Jan-10 17:29
marlonskie103027-Jan-10 17:29 
GeneralRe: unathorized Pin
Farhad Navaei13-Sep-12 11:33
Farhad Navaei13-Sep-12 11:33 
GeneralRe: unathorized Pin
Scott Bentley12-Oct-12 3:19
Scott Bentley12-Oct-12 3:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.