Thursday, November 2, 2017

Print multiple pages of SSRS report.


Nowadays we are not able to predict, how many records will be in report and how to break the report in a no of pages. There may be one or more then one page in a report. If we want to print all the pages of SSRS report, developer has to  implement some logical stuff.

Unfortunately, .NET Framework does not keep track of page numbers. Yet, It provides some facility to print multiple pages. Let's start:

Start to get byte[] of first page with the help of Reporting Service's Render() method.

string encoding, extension, mimeType, format = "IMAGE";
string deviceInfo = String.Format(@"<deviceinfo><outputformat><deviceinfo><outputformat>{0}</outputformat></deviceinfo></outputformat></deviceinfo>", "emf");
string[] streamIDs = null;
Warning[] warnings = null;

//Exectute the report and get page count.           
// Renders the first page of the report and returns streamIDs for 
// subsequent pages
firstPage = rs.Render(
    format,
    deviceInfo,
    out extension,
    out mimeType,
    out encoding,
    out warnings,
    out streamIDs);

Now, we have first page content in byte[] and first page is ready to print. In SQL Server 2005, streamIDs provide us the number of pages. Let me share one thing that beyond SQL Server 2008, calculating no of pages is impossible through streamIDs.

So, I have a solution:

we have the byte [] for our first page, but how will we get the byte code for our next pages? Is our question on top. Problem still remains.

 Now let's play with some techniques:

We need to create a dynamic device info, that will increment on the basis of pages. To do this, we will start with initializing two variables, one is integer with value 1 and other one is byte[][]. Assign the first page byte[] value in variable "pages" that is type of byte []. Add one local variable pageIndex and assign the value of m_numberOfPages, which is 1. This pageIndex variable will be number of pages. If we will pass 2 in this page index, it will give second page byte [], or if, we pass 3 then it will return third page byte[]. Do while loop will check the byte [] length for each page. It means device info is playing major role in printing.

Device info contains start page tag followed by passing the pageIndex value in startPage tag. See below snippet.
m_numberOfPages = 1;
pages = new Byte[m_numberOfPages][];

// The first page was already rendered
pages[0] = firstPage;

int pageIndex = m_numberOfPages;
do
{
    deviceInfo =
        String.Format(@"<deviceinfo><outputformat>{0}</outputformat><startpage>{1}</startpage></deviceinfo>",
            "emf", ++pageIndex);
    nextPage = rs.Render(format, deviceInfo, out extension, out mimeType, out encoding, out warnings, out streamIDs);
    if (nextPage.Length > 0)
    {
        Array.Resize(ref pages, ++m_numberOfPages);
        pages[m_numberOfPages - 1] = nextPage;
    }
}
while (nextPage.Length > 0);

This code snippet will provide the byte [] for all the pages of report. Now we have all the pages byte[] array,  which we will pass to initialize the memory stream object, then send a command on printer to print the records. Complete code of this project is available from the download link :). Download

No comments:

Post a Comment

Create Entity Framework Model classes through EF Core with Database First approach.

Today, we will walkthrough about .Net Core with EF Core (Data First approach). In this article, we will learn to create Entity Framework ...