How to add Cross-Browser Printing to ASP.NET ReportViewer toolbar
Product WebClientPrint for ASP.NET Published 04/15/2013 Updated 11/06/2013 Author Neodynamic
Overview
By default, the ASP.NET ReportViewer control enables client-side printing when the user browser is Internet Explorer only. If the user opens to the report page through Firefox or Chrome, then ReportViewer will hide the Print button from the toolbar. This happens because the built-in client-side printing mechanism (a.k.a. RSPrintClient.cab) was designed and developed by using ActiveX which is not supported by other browsers but just by IE.
In this walkthrough, you'll learn how to add cross-browser printing to the ASP.NET ReportViewer control that works with any browser on Windows OS like IE (6 or later), Chrome, Firefox, Opera & Safari as well as on Linux & Mac OS machines! After following this guide, you'll get the following custom print elements on the ReportViewer toolbar:
ASP.NET ReportViewer Custom Toolbar listing Installed Client Printers and Print button on Chrome
The code provided by this walkthrough allows you:
To add a custom drop-down-list of the printers installed at the client machine!
To print the RDLC report to the Default Printer or any installed printer without displaying any dialog!
To provide the client-side printing feature to any browser on Windows OS like IE, Firefox, Chrome, Opera & Safari as well as on Linux & Mac OS clients!
To test this Cross-Browser printing solution we provide you a sample Local Report RDLC featuring a products list for MS Northwind Traders database.
Requirements
Development/Server-side
WebClientPrint 2.0 for ASP.NET (or greater)
ASP.NET 3.5 (or greater)
Visual Studio 2010 / VWD 2010 (or greater)
jQuery 1.4.1 (or greater)
Client-side
WebClientPrint Processor 2.0 for Windows, Linux & Mac (WCPP) - Part of WebClientPrint Solution
Adobe Reader or Foxit Reader (Only for Windows clients; No additional requirements for Linux & Mac systems)
Follow up these steps
- Download & install WebClientPrint for ASP.NET
- Open Visual Studio and create a new ASP.NET 3.5 Website naming it PrintRDLCReport
- Add a reference to Neodynamic.SDK.WebClientPrint.dll to your project
-
Open your web.config file and add the following entries:
<system.web> ... <httpHandlers> ... <add verb="*" path="wcp.axd" type="Neodynamic.SDK.Web.WebClientPrint, Neodynamic.SDK.WebClientPrint"/> ... </httpHandlers> ... </system.web> <system.webServer> ... <handlers> ... <add name="WCP" verb="*" path="wcp.axd" type="Neodynamic.SDK.Web.WebClientPrint, Neodynamic.SDK.WebClientPrint"/> ... </handlers> ... </system.webServer>
-
Open the default.aspx page and paste the following markup. The task of this page is to try to detect the WCPP and inform the user to install it if it's missing.
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <style> body{font: 13px 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;} </style> <%-- WCPP-detection meta tag for IE10 --%> <%= Neodynamic.SDK.Web.WebClientPrint.GetWcppDetectionMetaTag() %> </head> <body> <form id="form1" runat="server"> <div id="msgInProgress"> <div id="mySpinner" style="width:32px;height:32px"></div> <br /> Detecting WCPP utility at client side... <br /> Please wait a few seconds... <br /> </div> <div id="msgInstallWCPP" style="display:none;"> <h3>#1 Install WebClientPrint Processor (WCPP)!</h3> <p> <strong>WCPP is a native app (without any dependencies!)</strong> that handles all print jobs generated by the <strong>WebClientPrint ASP.NET component</strong> at the server side. The WCPP is in charge of the whole printing process and can be installed on <strong>Windows, Linux & Mac!</strong> </p> <p> <a href="http://www.neodynamic.com/downloads/wcpp/" target="_blank">Download and Install WCPP from Neodynamic website</a><br /> </p> <h3>#2 After installing WCPP...</h3> <p> <a href="ReportViewerCrossBrowserClientPrint.aspx">You can go and test WebClientPrint for ASP.NET</a> </p> </div> </form> <%-- Add Reference to jQuery at Google CDN --%> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <%-- Add Reference to spin.js (an animated spinner) --%> <script src="//spin.js.org/spin.js"></script> <script type="text/javascript"> var wcppPingDelay_ms = 10000; function wcppDetectOnSuccess(){ <%-- WCPP utility is installed at the client side redirect to WebClientPrint sample page --%> <%-- get WCPP version --%> var wcppVer = arguments[0]; if(wcppVer.substring(0, 1) == "2") window.location.href = "ReportViewerCrossBrowserClientPrint.aspx"; else //force to install WCPP v2.0 wcppDetectOnFailure(); } function wcppDetectOnFailure() { <%-- It seems WCPP is not installed at the client side ask the user to install it --%> $('#msgInProgress').hide(); $('#msgInstallWCPP').show(); } $(document).ready(function () { <%-- Create the Spinner with options (http://fgnass.github.io/spin.js/) --%> var spinner = new Spinner({ lines: 12, length: 7, width: 3, radius: 10, color: '#336699', speed: 1, trail: 60 }).spin($('#mySpinner')[0]); }); </script> <%-- WCPP detection script --%> <%= Neodynamic.SDK.Web.WebClientPrint.CreateWcppDetectionScript() %> </body> </html>
-
The Local Report RDLC we've created for this sample is a simple product list for MS Northwind Traders database and it has an XML data source. The report looks like the following figure.
Sample RDLC report featuring Northwind Traders product list
- Download and copy both MyReport.rdlc & NorthwindProducts.xml files to your website root folder
-
Finally, add a new ASPX page and name it ReportViewerCrossBrowserClientPrint.aspx (be sure to UNSELECT the "Place code in separate file" checkbox)
In this page, we'll customize the ReportViewer toolbar by adding a list of installed client printers and our own Print button. The user will be able to print to the Defaul Printer or any other installed printer without displaying any print dialog!
At server-side, we convert the report to PDF format and then we pass it to the WCPP utility to print it to the desired client printer. For Windows clients, the user is required to have Adobe Reader installed to get this code working.
Please paste the following markup and code depending on your preferred language i.e. C# or VB on your ReportViewerCrossBrowserClientPrint.aspx file.VB
<%@ Page Language="VB" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Collections.Generic" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="Neodynamic.SDK.Web" %> <%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %> <!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 Page_Init(sender As Object, e As System.EventArgs) 'Print report??? If (WebClientPrint.ProcessPrintJob(Request)) Then 'create PDF version of RDLC report Dim myReport As New LocalReport() myReport.ReportPath = "MyReport.rdlc" Dim ds As New DataSet() ds.ReadXml(Server.MapPath("~/NorthwindProducts.xml")) myReport.DataSources.Add(New ReportDataSource("Products", ds.Tables(0))) Dim deviceInfo As String = _ "
" + _ " " 'Export to PDF. Get binary content. Dim pdfContent As Byte() = myReport.Render("PDF", deviceInfo, Nothing, Nothing, Nothing, Nothing, Nothing) 'Now send this file to the client side for printing 'IMPORTANT: Adobe Reader needs to be installed at the client side 'Get printer name Dim printerName As String = Server.UrlDecode(Request("printerName")); 'create a temp file name for our PDF report... Dim fileName As String = "MyFile-" + Guid.NewGuid().ToString("N") + ".pdf" 'Create a PrintFile object with the pdf report Dim file As New PrintFile(pdfContent, fileName) 'Create a ClientPrintJob and send it back to the client! Dim cpj As New ClientPrintJob() 'set file to print... cpj.PrintFile = file 'set client printer... If (printerName = "Default Printer") Then cpj.ClientPrinter = New DefaultPrinter() Else cpj.ClientPrinter = New InstalledPrinter(printerName) End If 'send it... cpj.SendToClient(Response) End If End Sub Protected Sub Page_Load(sender As Object, e As System.EventArgs) If (IsPostBack = False) Then 'load report in case user want to preview it ReportViewer1.ProcessingMode = ProcessingMode.Local ReportViewer1.LocalReport.ReportPath = "MyReport.rdlc" Dim ds As New DataSet() ds.ReadXml(Server.MapPath("~/NorthwindProducts.xml")) ReportViewer1.LocalReport.DataSources.Add(New ReportDataSource("Products", ds.Tables(0))) End If End Sub </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Print Local Report RDLC without Previewing nor Print Dialog!</title> <style> body{font: 13px 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;background:#ddd;color:#333;margin:0;} h1{background:#333;color:#fff;padding:10px;font: 29px 'Segoe UI Light', 'Tahoma Light', 'Arial Light', 'Helvetica Light', sans-serif;} .myRow{width:auto;padding:0 20px 0 20px;height:auto;} </style> </head> <body> <%-- Store User's SessionId --%> <input type="hidden" id="sid" name="sid" value="<%=Session.SessionID%>" /> <form id="form1" runat="server"> <h1>ReportViewer with Cross-Browser Client Print</h1> <div class="myRow" style="clear:both" id="pnlReport"> <br /><br /> <rsweb:ReportViewer ID="ReportViewer1" runat="server" Height="450px" Width="960px"> </rsweb:ReportViewer> </div> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> </form> <%-- Add Reference to jQuery at Google CDN --%> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <%-- Register the WebClientPrint script code --%> <%=Neodynamic.SDK.Web.WebClientPrint.CreateScript()%> <script type="text/javascript"> $(document).ready(function () { <%-- hide built-in print button from ReportViewer toolbar --%> $('table[title="Print"]').hide(); <%-- embed custom DropDownList for listing installed client printers and print image button --%> $('#<%=ReportViewer1.ClientID%>_ctl05:last-child').children().append('<div class=" " style="display:inline-block;font-family:Verdana;font-size:8pt;vertical-align:top;"><table cellpadding="0" cellspacing="0" style="display:inline;"><tbody><tr><td height="28px"><select name="ddlClientPrinters" id="ddlClientPrinters" style="font-family:Verdana;font-size:8pt;" title="Select Printer"><option>Loading printers...</option></select></td><td width="4px"></td><td height="28px"><div><div id="<%=ReportViewer1.ClientID%>_Custom_Print_Button" style="border: 1px solid transparent; background-color: transparent; cursor: default;"><table title="Print"><tbody><tr><td><input type="image" title="Print" src="Reserved.ReportViewerWebControl.axd?OpType=Resource&Name=Microsoft.Reporting.WebForms.Icons.Print.gif" alt="Refresh" style="border-style:None;height:16px;width:16px;border-width:0px;"></td></tr></tbody></table></div></div></td></tr></tbody></table></div>'); <%-- mouse hover effect for our new print image button --%> $('#<%=ReportViewer1.ClientID%>_Custom_Print_Button').hover(function() { //hover style $(this).css({'border': '1px solid #336699', 'background-color': '#DDEEF7', 'cursor': 'pointer'}); }, function() { //normal style $(this).css({'border': '1px solid transparent', 'background-color': 'transparent', 'cursor': 'default'}) }); <%-- load client printers through WebClientPrint --%> jsWebClientPrint.getPrinters(); <%-- add click handler for print button --%> $('#<%=ReportViewer1.ClientID%>_Custom_Print_Button').click(function() { jsWebClientPrint.print('printerName=' + $('#ddlClientPrinters').val()); }); }); <%-- Time delay we'll wait for getting client printer names --%> var wcppGetPrintersDelay_ms = 5000; //5 sec function wcpGetPrintersOnSuccess(){ <%-- Display client installed printers --%> if(arguments[0].length > 0){ var p=arguments[0].split("|"); var options = '<option>Default Printer</option>'; for (var i = 0; i < p.length; i++) { options += '<option>' + p[i] + '</option>'; } $('#ddlClientPrinters').html(options); }else{ alert("No printers are installed in your system."); } } function wcpGetPrintersOnFailure() { <%-- Do something if printers cannot be got from the client --%> alert("No printers are installed in your system."); } </script> </body> </html>PDF " + _ "8.5in " + _ "11in " + _ "0.5in " + _ "0.75in " + _ "0.5in " + _ "0.5in " + _ "C#
<%@ Page Language="C#" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Collections.Generic" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="Neodynamic.SDK.Web" %> <%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %> <!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 Page_Init(object sender, EventArgs e) { //Print report??? if (WebClientPrint.ProcessPrintJob(Request)) { //create PDF version of RDLC report LocalReport myReport = new LocalReport(); myReport.ReportPath = "MyReport.rdlc"; DataSet ds = new DataSet(); ds.ReadXml(Server.MapPath("~/NorthwindProducts.xml")); myReport.DataSources.Add(new ReportDataSource("Products", ds.Tables[0])); //Export to PDF. Get binary content. string mimeType; string encoding; string fileNameExtension; string[] streams; Warning[] warnings; string deviceInfo = "
" + " "; byte[] pdfContent = myReport.Render("PDF", deviceInfo, out mimeType, out encoding, out fileNameExtension, out streams, out warnings); //Now send this file to the client side for printing //IMPORTANT: Adobe Reader needs to be installed at the client side //Get printer name string printerName = Server.UrlDecode(Request["printerName"]); //create a temp file name for our PDF report... string fileName = "MyFile-" + Guid.NewGuid().ToString("N") + ".pdf"; //Create a PrintFile object with the pdf report PrintFile file = new PrintFile(pdfContent, fileName); //Create a ClientPrintJob and send it back to the client! ClientPrintJob cpj = new ClientPrintJob(); //set file to print... cpj.PrintFile = file; //set client printer... if (printerName == "Default Printer") cpj.ClientPrinter = new DefaultPrinter(); else cpj.ClientPrinter = new InstalledPrinter(printerName); //send it... cpj.SendToClient(Response); } } protected void Page_Load(object sender, EventArgs e) { if (IsPostBack == false) { //load report in case user want to preview it ReportViewer1.ProcessingMode = ProcessingMode.Local; ReportViewer1.LocalReport.ReportPath = "MyReport.rdlc"; DataSet ds = new DataSet(); ds.ReadXml(Server.MapPath("~/NorthwindProducts.xml")); ReportViewer1.LocalReport.DataSources.Add(new ReportDataSource("Products", ds.Tables[0])); } } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Print Local Report RDLC without Previewing nor Print Dialog!</title> <style> body{font: 13px 'Segoe UI', Tahoma, Arial, Helvetica, sans-serif;background:#ddd;color:#333;margin:0;} h1{background:#333;color:#fff;padding:10px;font: 29px 'Segoe UI Light', 'Tahoma Light', 'Arial Light', 'Helvetica Light', sans-serif;} .myRow{width:auto;padding:0 20px 0 20px;height:auto;} </style> </head> <body> <%-- Store User's SessionId --%> <input type="hidden" id="sid" name="sid" value="<%=Session.SessionID%>" /> <form id="form1" runat="server"> <h1>ReportViewer with Cross-Browser Client Print</h1> <div class="myRow" style="clear:both" id="pnlReport"> <br /><br /> <rsweb:ReportViewer ID="ReportViewer1" runat="server" Height="450px" Width="960px"> </rsweb:ReportViewer> </div> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> </form> <%-- Add Reference to jQuery at Google CDN --%> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <%-- Register the WebClientPrint script code --%> <%=Neodynamic.SDK.Web.WebClientPrint.CreateScript()%> <script type="text/javascript"> $(document).ready(function () { <%-- hide built-in print button from ReportViewer toolbar --%> $('table[title="Print"]').hide(); <%-- embed custom DropDownList for listing installed client printers and print image button --%> $('#<%=ReportViewer1.ClientID%>_ctl05:last-child').children().append('<div class=" " style="display:inline-block;font-family:Verdana;font-size:8pt;vertical-align:top;"><table cellpadding="0" cellspacing="0" style="display:inline;"><tbody><tr><td height="28px"><select name="ddlClientPrinters" id="ddlClientPrinters" style="font-family:Verdana;font-size:8pt;" title="Select Printer"><option>Loading printers...</option></select></td><td width="4px"></td><td height="28px"><div><div id="<%=ReportViewer1.ClientID%>_Custom_Print_Button" style="border: 1px solid transparent; background-color: transparent; cursor: default;"><table title="Print"><tbody><tr><td><input type="image" title="Print" src="Reserved.ReportViewerWebControl.axd?OpType=Resource&Name=Microsoft.Reporting.WebForms.Icons.Print.gif" alt="Refresh" style="border-style:None;height:16px;width:16px;border-width:0px;"></td></tr></tbody></table></div></div></td></tr></tbody></table></div>'); <%-- mouse hover effect for our new print image button --%> $('#<%=ReportViewer1.ClientID%>_Custom_Print_Button').hover(function() { //hover style $(this).css({'border': '1px solid #336699', 'background-color': '#DDEEF7', 'cursor': 'pointer'}); }, function() { //normal style $(this).css({'border': '1px solid transparent', 'background-color': 'transparent', 'cursor': 'default'}) }); <%-- load client printers through WebClientPrint --%> jsWebClientPrint.getPrinters(); <%-- add click handler for print button --%> $('#<%=ReportViewer1.ClientID%>_Custom_Print_Button').click(function() { jsWebClientPrint.print('printerName=' + $('#ddlClientPrinters').val()); }); }); <%-- Time delay we'll wait for getting client printer names --%> var wcppGetPrintersDelay_ms = 5000; //5 sec function wcpGetPrintersOnSuccess(){ <%-- Display client installed printers --%> if(arguments[0].length > 0){ var p=arguments[0].split("|"); var options = '<option>Default Printer</option>'; for (var i = 0; i < p.length; i++) { options += '<option>' + p[i] + '</option>'; } $('#ddlClientPrinters').html(options); }else{ alert("No printers are installed in your system."); } } function wcpGetPrintersOnFailure() { <%-- Do something if printers cannot be got from the client --%> alert("No printers are installed in your system."); } </script> </body> </html>PDF " + "8.5in " + "11in " + "0.5in " + "0.75in " + "0.5in " + "0.5in " + " - That's it! Run your website and test it. WebClientPrint will load the installed printers at the client machine and will list it in the ReportViewer toolbar. User can select any of the installed printers and by clicking on Print icon button (that now will be available in IE, Firefox, Chrome, Opera or Safari on Windows, Linux & Mac) the printing process will be performed.
On Windows clients, Adobe Reader stays open after printing
That's a known behavior of Adobe Reader 8.0 or greater. There's no way to close it from our part, sadly. The only suggestion is to install Foxit Reader (a free PDF Viewer) instead. If Foxit Reader is installed, the printing is performed without displaying it to the end user!