Show / Hide Table of Contents

The WebClientPrint Server Component

Overview

WebClientPrint is a client-server solution. The server-side component is a .NET Class Library (Neodynamic.SDK.WebClientPrintCore.dll) which is referenced by your ASP.NET website to generate Client Print Jobs.

A Client Print Job allows you to specify:

  • Which client printer to use, for example:
    • Use "the Default printer" of the client machine. Printing will be performed without displaying any dialog!
    • Use "a specific installed printer name" on the client machine. Printing will be performed without displaying any dialog! This also applies for Shared Printers on the client machine network with a UNC name/path!
    • Display a "printer dialog" to let the user to select the printer
    • Explicitly specify the client printer settings for parallel (LPT) Centronics or serial RS-232 ports or IP/Ethernet Network printers.
  • And the commands or file you want to print or send to the client printer.

The WebClientPrint server component requires:

  • ASP.NET 2.0+
  • jQuery 1.4.1+

Client Print Jobs

A Client Print Job (CPJ) contains info about the print job to be processed at the client side by the WCPP utility. The info includes the type of printer to be used and that is available at the client side as well as the data, text or raw commands you want to send or print to such printer.

Creating Client Print Jobs

A CPJ is specified by creating an instance of the ClientPrintJob class. The target client printer is specified through the ClientPrinter property and the data, text or raw commands are specified through the PrinterCommands property. That's it! The Client Printer Types and Printer Commands topics below provide details and sample code of those main properties.

Client Printer Types

The Client Printer is specified through the ClientPrinter property and it accepts an object that should be an instance of any of the following ClientPrint-derived classes:

  • DefaultPrinter
  • UserSelectedPrinter
  • InstalledPrinter
  • ParallelPortPrinter
  • SerialPortPrinter
  • NetworkPrinter

Read on to see how to create CPJ for each of the supported client printer types.

DefaultPrinter

The DefaultPrinter allows you to print to the client's printer which is set up as the "default printer". The printing is performed without displaying any dialog to the user. Here is a snippet code of how to use this option:

C#
using Neodynamic.SDK.Web;

//...

//Create a ClientPrintJob obj that will be processed at the client side by the WCPP
ClientPrintJob cpj = new ClientPrintJob();

//use default printer on the client machine
cpj.ClientPrinter = new DefaultPrinter();

//set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE";
VB
Imports Neodynamic.SDK.Web

'...

'Create a ClientPrintJob obj that will be processed at the client side by the WCPP
Dim cpj As New ClientPrintJob()

'use default printer on the client machine
cpj.ClientPrinter = New DefaultPrinter()

'set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE"

UserSelectedPrinter

The UserSelectedPrinter allows you to let the user to dynamically select which printer he/she wants to use by displaying a Print Dialog box. That print dialog will list all the installed printers in the user's machine. Here is a snippet code of how to use this option:

C#
using Neodynamic.SDK.Web;

//...

//Create a ClientPrintJob obj that will be processed at the client side by the WCPP
ClientPrintJob cpj = new ClientPrintJob();

//let the user to select the printer by a print dialog box
cpj.ClientPrinter = new UserSelectedPrinter();

//set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE";
VB
Imports Neodynamic.SDK.Web

'...

'Create a ClientPrintJob obj that will be processed at the client side by the WCPP
Dim cpj As New ClientPrintJob()

'let the user to select the printer by a print dialog box
cpj.ClientPrinter = New UserSelectedPrinter()

'set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE"

InstalledPrinter

The InstalledPrinter allows you to specify the "Printer Name" of an installed printer at the client machine. By "installed" it means, a printer which is listed in the Printers section of Windows, Linux or Mac OS. Those printers are generally installed by using a driver provided by the manufacturer.

For Raw printing, installing the "Generic / Text Only" driver that comes with Windows OS (and similar driver on Linux & Mac OS) is sufficient in many cases. The "Generic / Text Only" driver is also useful when you cannot get the original driver from the manufacturer because it does not support a given version of Windows or the printer is too old, etc.

So, suppose the user has a printer installed which name is "MyLocalPrinter". Here is a snippet code of how to use this option:

C#
using Neodynamic.SDK.Web;

//...

//Create a ClientPrintJob obj that will be processed at the client side by the WCPP
ClientPrintJob cpj = new ClientPrintJob();

//set the installed printer's name on the client machine
cpj.ClientPrinter = new InstalledPrinter("MyLocalPrinter");

//set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE";
VB
Imports Neodynamic.SDK.Web

'...

'Create a ClientPrintJob obj that will be processed at the client side by the WCPP
Dim cpj = New ClientPrintJob()

'set the installed printer's name on the client machine
cpj.ClientPrinter = New InstalledPrinter("MyLocalPrinter")

'set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE"

Special case for Shared Network printers: When the user has an installed printer which is a Shared Network Printer (i.e. a printer attached to another computer on the network), then you can use the InstalledPrinter option to specify such kind of printer. The correct way to specify the printer's name in these cases is by using the UNC (Universal Naming Convention) name/path to reach the printer.

So, suppose the user has a network printer installed which UNC path is "\anotherPC\CoolBrandPrinter". Here is a snippet code of how to use this option:

C#
using Neodynamic.SDK.Web;

//...

//Create a ClientPrintJob obj that will be processed at the client side by the WCPP
ClientPrintJob cpj = new ClientPrintJob();

//set the installed network printer's UNC path/name
cpj.ClientPrinter = new InstalledPrinter("\\anotherPC\CoolBrandPrinter");

//set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE";
VB
Imports Neodynamic.SDK.Web

'...

'Create a ClientPrintJob obj that will be processed at the client side by the WCPP
Dim cpj As New ClientPrintJob()

'set the installed network printer's UNC path/name
cpj.ClientPrinter = New InstalledPrinter("\\anotherPC\CoolBrandPrinter")

'set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE"

You can also specify the Tray Name as well as the Paper Name to be used by the specified printer when printing the following file formats: PNG, JPG, BMP, TXT & PDF

ParallelPortPrinter

The ParallelPortPrinter allows you to specify the parallel port (LPT) of the client machine that the printer is connected to. The client does not need to install the printer through Windows OS. However, a valid LPT port needs to be available and the printer connected to such port through a Centronics interface.

For Linux & Mac OS, Parallel Port printers must be installed through CUPS and then set the assigned printer name through the InstalledPrinter option.

Here is a snippet code of how to use this option:

C#
using Neodynamic.SDK.Web;

//...

//Create a ClientPrintJob obj that will be processed at the client side by the WCPP
ClientPrintJob cpj = new ClientPrintJob();

//use the printer available at LPT1 port on the client machine
cpj.ClientPrinter = new ParallelPortPrinter("LPT1");

//set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE";
VB
Imports Neodynamic.SDK.Web

'...

'Create a ClientPrintJob obj that will be processed at the client side by the WCPP
Dim cpj As New ClientPrintJob()

'use the printer available at LPT1 port on the client machine
cpj.ClientPrinter = New ParallelPortPrinter("LPT1")

'set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE"

SerialPortPrinter

The SerialPortPrinter allows you to specify the serial port (RS-232) settings of the client printer. The client does not need to install the printer through Windows OS. However, a valid serial port needs to be available and the printer connected to such port. Please refer to the client's printer manual for details about the serial port settings.

For Linux & Mac OS, Serial RS232 Port printers must be installed through CUPS and then set the assigned printer name through the InstalledPrinter option.

Here is a snippet code of how to use this option:

C#
using Neodynamic.SDK.Web;

//...

//Create a ClientPrintJob obj that will be processed at the client side by the WCPP
ClientPrintJob cpj = new ClientPrintJob();

//use the printer available at COM1 port and these settings
//NOTE: Refer to the printer manual for details
cpj.ClientPrinter = new SerialPortPrinter("COM1", 9600, SerialPortParity.None, SerialPortStopBits.One, 8, SerialPortHandshake.XOnXOff);

//set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE";
VB
Imports Neodynamic.SDK.Web

'...

'Create a ClientPrintJob obj that will be processed at the client side by the WCPP
Dim cpj As New ClientPrintJob()

'use the printer available at COM1 port and these settings
'NOTE: Refer to the printer manual for details
cpj.ClientPrinter = New SerialPortPrinter("COM1", 9600, SerialPortParity.None, SerialPortStopBits.One, 8, SerialPortHandshake.XOnXOff)

'set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE"

NetworkPrinter

The NetworkPrinter allows you to specify a TCP/IP Ethernet-enabled printer that can be reached from the client machine. The client printer in this case can be specified by using the IP address or DNS name as well as the port number.

For Linux & Mac OS, IP/Ethernet printers should be installed through CUPS and then set the assigned printer name through the InstalledPrinter option.

Here is a snippet code of how to use this option:

C#
using Neodynamic.SDK.Web;

//...

//Create a ClientPrintJob obj that will be processed at the client side by the WCPP
ClientPrintJob cpj = new ClientPrintJob();

//set the printer's IP address or DNS name and port number
cpj.ClientPrinter = new NetworkPrinter("10.0.0.8", 9100);

//set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE";
VB
Imports Neodynamic.SDK.Web

'...

'Create a ClientPrintJob obj that will be processed at the client side by the WCPP
Dim cpj As New ClientPrintJob()

'set the printer's IP address or DNS name and port number
cpj.ClientPrinter = New NetworkPrinter("10.0.0.8", 9100)

'set the commands to send to the printer
cpj.PrinterCommands = "PRINTER_COMMANDS_GO_HERE"

Printer Commands (RAW Data Printing)

The printer commands you want to send to the client printer is specified through the PrinterCommands property of the ClientPrintJob class. The PrinterCommands property accepts a String type. However, if your printer commands are stored in a physical file on disk or in a database, then you can use the BinaryPrinterCommands properties instead as it accepts a byte array which is suitable for these scenarios.

String Format for Printer Commands

As stated before, the PrinterCommands property accepts a String type for the commands you want to send to the client printer through a ClientPrintJob object.

Some Printer Command/Programming Languages feature non-printable or non-human-readable characters in their syntax. Common samples are the ESC/P language which uses ASCII Dec 27 (ESC), ASCII Dec 10 (LF), ASCII Dec 13 (CR), etc; thermal printer languages like Zebra ZPL which sometimes needs to specify ASCII Dec 29 (GS), ASCII Dec 30 (RS), ASCII Dec 4 (EOT), etc.

These non-printable chars could require many string concatenations with VB or C#. To avoid such situation and to provide a better readability of your printer commands, WebClientPrint allows you to format any character by expressing it in VB or C# Hexadecimal notation within the string commands.

For example, suppose you need to send ESC/P codes for "Set page length in inches" which syntax is as follows: [ESC] C [NUL] n

Where:

  • [ESC]: is ASCII Hex 1B
  • C: is ASCII Hex 43
  • [NUL]: is ASCII 00
  • n: is a number in the range 1 < n < 22

Then to specify this command as a string and using the VB or C# Hexadecimal notation:

C#
//set the commands to send to the printer
cpj.PrinterCommands = "0x1B C 0x00 5";

//enable Hex notation for commands
cpj.FormatHexValues = true;
VB
'set the commands to send to the printer
cpj.PrinterCommands = "&H1B C &H00 5"

'enable Hex notation for commands
cpj.FormatHexValues = True

Binary Format for Printer Commands

As stated before, the BinaryPrinterCommands property accepts a byte array for the commands you want to send to the client printer through a ClientPrintJob object. You can get such bytes from anywhere but common scenarios are files on disk or databases. Here is a snippet of how you could get and set the printer commands stored in a file on disk. In this sample code we get the printer commands from a PRN file.

C#
//get and set the commands to send to the printer from a file
cpj.BinaryPrinterCommands = System.IO.File.ReadAllBytes("c:/temp/invoice.prn");
VB
'get and set the commands to send to the printer from a file
cpj.BinaryPrinterCommands = System.IO.File.ReadAllBytes("c:/temp/invoice.prn")

Printing Common File Formats

In addition to print native commands, you can also use WebClientPrint solution to send and print common file formats like PDF, TXT, DOC, XLS, JPG, PNG, TIFF (Multipage), etc.

The Print File feature has the following requirements:

File Format Windows Clients Linux & Mac Clients
DOC, DOCX Microsoft Word is required LibreOffice is required
XLS, XLSX Microsoft Excel is required LibreOffice is required
PDF Natively supported! Natively supported!
TXT Natively supported! Natively supported!
JPEG Natively supported! Natively supported!
PNG Natively supported! Natively supported!
BMP Natively supported! Natively supported!
Printer Support You can print files to local installed printers ONLY! Parallel, Serial and IP/Ethernet printers are NOT supported. You can print files to any installed printers through CUPS system.

The file you want to send to the client printer is specified through the PrintFile property of the ClientPrintJob class. The PrintFile property accepts an instance of the PrintFile type.

The source code of the WebClientPrint Sample Website at github has a complete code for testing this feature.

Printing multiple files is possible too!

In addition to printing a single file, you can send to the client printer multiple files! For example, you could want to print a PDF file, plus an image file. Or multiple Word docs plus other Excel sheets!

The files you want to send to the client printer are specified through the PrintFileGroup property of the ClientPrintJob class. The PrintFileGroup property is a collection of objects that are instances of the PrintFile type.

Checkout the WebClientPrint Articles section for sample code about this topic.

Printing multiple ClientPrintJob objects with one shot!

Suppose you need to send raw commands to a printer and at the same time print a document to another one, all in just one click... In these cases, the brand new ClientPrintJobGroup class comes to the rescue. You can create as many individual ClientPrintJob objects as you need and then specify them to the ClientPrintJobGroup class to get them processed at the client machine by the WCPP utility.

Checkout the WebClientPrint Articles section for sample code about this topic.

Sending the ClientPrintJob to the client

After you create a ClientPrintJob object, set its main properties like the target ClientPrinter and the PrinterCommands or PrintFile you want to print; then the final step is to send the ClientPrintJob to the client machine from your ASP.NET website. This must be done from a Controller or HTTP Handler class where you have to return the binary content which will be created by invoking the ClientPrintJob Content and specifying the MIME Type as "application/octet-stream".

The source code of the WebClientPrint Sample Website at github has a complete code for this topic so please take a look at it!

WebClientPrint Scripting

The WebClientPrint Server Component allows you create ClientPrintJob objects that are sent to the client machine where the WCPP utility will process them. To launch the WCPP installed at the client machine, you need to add some script code to your View or WebForm page. The WebClientPrint class provides you with all the needed to perform this task without efforts at all.

Creating the WebClientPrintAPI Class

For ASP.NET MVC Projects

Before you can use the WebClientPrint solution in your ASP.NET MVC website, the first thing to do is to create a new Controller and name it WebClientPrintAPIController

After WebClientPrintAPIController class is created, copy/paste the following code:

C#

using System;
using System.Web;
using System.Web.Mvc;

using Neodynamic.SDK.Web;

namespace WebClientPrint4MVC5CS.Controllers
{
    //*********************************
    // IMPORTANT NOTE 
    // In this sample we store users related stuff (like
    // the list of printers and whether they have the WCPP 
    // client utility installed) in the Application cache
    // object part of ASP.NET BUT you can change it to 
    // another different storage (like a DB or file server)!
    // which will be required in Load Balacing scenarios
    //*********************************

    public class WebClientPrintAPIController : Controller
    {
        [AllowAnonymous]
        public void ProcessRequest()
        {
            //get session ID
            string sessionID = (HttpContext.Request["sid"] != null ? HttpContext.Request["sid"] : null);

            //get Query String
            string queryString = HttpContext.Request.Url.Query;

            try
            {
                //Determine and get the Type of Request 
                RequestType prType = WebClientPrint.GetProcessRequestType(queryString);

                if (prType == RequestType.GenPrintScript ||
                    prType == RequestType.GenWcppDetectScript)
                {
                    //Let WebClientPrint to generate the requested script
                    byte[] script = WebClientPrint.GenerateScript(Url.Action("ProcessRequest", "WebClientPrintAPI", null, HttpContext.Request.Url.Scheme), queryString);

                    HttpContext.Response.ContentType = "text/javascript";
                    HttpContext.Response.BinaryWrite(script);
                    HttpContext.Response.End();
                }
                else if (prType == RequestType.ClientSetWcppVersion)
                {
                    //This request is a ping from the WCPP utility
                    //so store the session ID indicating it has the WCPP installed
                    //also store the WCPP Version if available
                    string wcppVersion = HttpContext.Request["wcppVer"];
                    if (string.IsNullOrEmpty(wcppVersion))
                        wcppVersion = "1.0.0.0";

                    HttpContext.Application.Set(sessionID + "wcppInstalled", wcppVersion);
                }
                else if (prType == RequestType.ClientSetInstalledPrinters)
                {
                    //WCPP Utility is sending the installed printers at client side
                    //so store this info with the specified session ID
                    string printers = HttpContext.Request["printers"];
                    if (string.IsNullOrEmpty(printers) == false)
                        printers = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(printers));

                    HttpContext.Application.Set(sessionID + "printers", printers);

                }
                else if (prType == RequestType.ClientSetInstalledPrintersInfo)
                {
                    //WCPP Utility is sending the client installed printers with detailed info
                    //so store this info with the specified session ID
                    //Printers Info is in JSON format
                    string printersInfo = HttpContext.Request.Form["printersInfoContent"];

                    if (string.IsNullOrEmpty(printersInfo) == false)
                        printersInfo = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(printersInfo));

                    HttpContext.Application.Set(sessionID + "printersInfo", printersInfo);


                }
                else if (prType == RequestType.ClientGetWcppVersion)
                {
                    //return the WCPP version for the specified sid if any
                    bool sidWcppVersion = (HttpContext.Application.Get(sessionID + "wcppInstalled") != null);

                    HttpContext.Response.ContentType = "text/plain";
                    HttpContext.Response.Write((sidWcppVersion ? HttpContext.Application.Get(sessionID + "wcppInstalled") : ""));
                    HttpContext.Response.End();

                }
                else if (prType == RequestType.ClientGetInstalledPrinters)
                {
                    //return the installed printers for the specified sid if any
                    bool sidHasPrinters = (HttpContext.Application.Get(sessionID + "printers") != null);

                    HttpContext.Response.ContentType = "text/plain";
                    HttpContext.Response.Write((sidHasPrinters ? HttpContext.Application.Get(sessionID + "printers") : ""));
                    HttpContext.Response.End();
                }
                else if (prType == RequestType.ClientGetInstalledPrintersInfo)
                {
                    //return the installed printers with detailed info for the specified Session ID (sid) if any
                    bool sidHasPrinters = (HttpContext.Application[sessionID + "printersInfo"] != null);

                    HttpContext.Response.ContentType = "text/plain";
                    HttpContext.Response.Write(sidHasPrinters ? HttpContext.Application[sessionID + "printersInfo"] : "");

                }

            }
            catch (Exception ex)
            {
                HttpContext.Response.StatusCode = 500;
                HttpContext.Response.ContentType = "text/plain";
                HttpContext.Response.Write(ex.Message + " - StackTrace: " + ex.StackTrace);
                HttpContext.Response.End();
            }


        }
    }
}
VB

Imports System.Web.Mvc

Imports Neodynamic.SDK.Web

Namespace Controllers
    Public Class WebClientPrintAPIController
        Inherits Controller

        ' GET: WebClientPrintAPI
        Function Index() As ActionResult
            Return View()
        End Function

        '*********************************
        ' IMPORTANT NOTE 
        ' In this sample we store users related stuff (like
        ' the list of printers and whether they have the WCPP 
        ' client utility installed) in the Application cache
        ' object part of ASP.NET BUT you can change it to 
        ' another different storage (like a DB or file server)!
        ' which will be required in Load Balacing scenarios
        '*********************************


        <AllowAnonymous>
        Public Sub ProcessRequest()
            'get session ID
            Dim sessionID As String = (If(HttpContext.Request("sid") IsNot Nothing, HttpContext.Request("sid"), Nothing))

            'get Query String
            Dim queryString As String = HttpContext.Request.Url.Query

            Try
                'Determine and get the Type of Request 
                Dim prType As RequestType = WebClientPrint.GetProcessRequestType(queryString)

                If prType = RequestType.GenPrintScript OrElse prType = RequestType.GenWcppDetectScript Then
                    'Let WebClientPrint to generate the requested script
                    Dim script As Byte() = WebClientPrint.GenerateScript(Url.Action("ProcessRequest", "WebClientPrintAPI", Nothing, HttpContext.Request.Url.Scheme), queryString)

                    HttpContext.Response.ContentType = "text/javascript"
                    HttpContext.Response.BinaryWrite(script)
                    HttpContext.Response.End()

                ElseIf prType = RequestType.ClientSetWcppVersion Then
                    'This request is a ping from the WCPP utility
                    'so store the session ID indicating it has the WCPP installed
                    'also store the WCPP Version if available
                    Dim wcppVersion As String = HttpContext.Request("wcppVer")
                    If String.IsNullOrEmpty(wcppVersion) Then
                        wcppVersion = "1.0.0.0"
                    End If

                    HttpContext.Application.Set(sessionID & "wcppInstalled", wcppVersion)

                ElseIf prType = RequestType.ClientSetInstalledPrinters Then
                    'WCPP Utility is sending the installed printers at client side
                    'so store this info with the specified session ID
                    Dim printers As String = HttpContext.Request("printers")
                    If String.IsNullOrEmpty(printers) = False Then
                        printers = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(printers))
                    End If


                    HttpContext.Application.Set(sessionID & "printers", printers)

                ElseIf prType = RequestType.ClientSetInstalledPrintersInfo Then
                    'WCPP Utility is sending the installed printers at client side
                    'so store this info with the specified session ID
                    'Printers Info is in JSON format
                    Dim printersInfo As String = HttpContext.Request.Form("printersInfoContent")
                    If Not String.IsNullOrEmpty(printersInfo) Then
                        printersInfo = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(printersInfo))
                    End If

                    HttpContext.Application.Set(sessionID & "printersInfo", printersInfo)


                ElseIf prType = RequestType.ClientGetWcppVersion Then
                    'return the WCPP version for the specified sid if any
                    Dim sidWcppVersion As Boolean = (HttpContext.Application(sessionID & "wcppInstalled") IsNot Nothing)

                    HttpContext.Response.ContentType = "text/plain"
                    If (sidWcppVersion) Then
                        HttpContext.Response.Write(HttpContext.Application(sessionID & "wcppInstalled").ToString())
                    End If
                    HttpContext.Response.End()

                ElseIf prType = RequestType.ClientGetInstalledPrinters Then
                    'return the installed printers for the specified sid if any
                    Dim sidHasPrinters As Boolean = (HttpContext.Application(sessionID & "printers") IsNot Nothing)

                    HttpContext.Response.ContentType = "text/plain"
                    If (sidHasPrinters) Then
                        HttpContext.Response.Write(HttpContext.Application(sessionID & "printers").ToString())
                    End If
                    HttpContext.Response.End()

                ElseIf prType = RequestType.ClientGetInstalledPrintersInfo Then
                    'return the installed printers with detailed info for the specified Session ID (sid) if any
                    Dim sidHasPrinters As Boolean = (HttpContext.Application(sessionID & "printersInfo") IsNot Nothing)

                    HttpContext.Response.ContentType = "text/plain"

                    If (sidHasPrinters) Then
                        HttpContext.Response.Write(HttpContext.Application(sessionID & "printersInfo").ToString())
                    End If
                    HttpContext.Response.End()
                End If
            Catch ex As Exception
                HttpContext.Response.StatusCode = 500
                HttpContext.Response.ContentType = "text/plain"
                HttpContext.Response.Write(ex.Message + " - StackTrace: " + ex.StackTrace)
                HttpContext.Response.End()
            End Try


        End Sub

    End Class
End Namespace

For ASP.NET WebForms Projects

Before you can use the WebClientPrint solution in your ASP.NET WebForms website, the first thing to do is to create a new Generic Handler and name it WebClientPrintAPI

After WebClientPrintAPI class is created, copy/paste the following code:

C#

using System;
using System.Web;
using System.IO;

using Neodynamic.SDK.Web;

public class WebClientPrintAPI : IHttpHandler {

    //*********************************
    // IMPORTANT NOTE 
    // In this sample we store users related stuff (like
    // the list of printers and whether they have the WCPP 
    // client utility installed) in the Application cache
    // object part of ASP.NET BUT you can change it to 
    // another different storage (like a DB or file server)!
    // which will be required in Load Balacing scenarios
    //*********************************

    public void ProcessRequest (HttpContext context) {
        //get session ID
        string sessionID = (context.Request["sid"] != null) ? context.Request["sid"].ToString() : null;

        //get Query String
        string queryString = context.Request.Url.Query;

        try
        {
            //Determine and get the Type of Request 
            RequestType prType = WebClientPrint.GetProcessRequestType(queryString);

            if (prType == RequestType.GenPrintScript ||
                prType == RequestType.GenWcppDetectScript)
            {
                //Let WebClientPrint to generate the requested script
                byte[] script = WebClientPrint.GenerateScript(context.Request.Url.AbsoluteUri.Replace(queryString, ""), queryString);

                context.Response.ContentType = "text/javascript";
                context.Response.BinaryWrite(script);
            }
            else if (prType == RequestType.ClientSetWcppVersion)
            {
                //This request is a ping from the WCPP utility
                //so store the session ID indicating this user has the WCPP installed
                //also store the WCPP Version if available
                string wcppVersion = context.Request["wcppVer"];
                if (string.IsNullOrEmpty(wcppVersion))
                    wcppVersion = "1.0.0.0";

                context.Application.Set(sessionID + "wcppInstalled", wcppVersion);
            }
            else if (prType == RequestType.ClientSetInstalledPrinters)
            {
                //WCPP Utility is sending the installed printers at client side
                //so store this info with the specified session ID
                string printers = context.Request["printers"];
                if (string.IsNullOrEmpty(printers) == false)
                    printers = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(printers));

                context.Application.Set(sessionID + "printers", printers);

            }
            else if (prType == RequestType.ClientSetInstalledPrintersInfo)
            {
                //WCPP Utility is sending the client installed printers with detailed info
                //so store this info with the specified session ID
                //Printers Info is in JSON format
                string printersInfo = context.Request.Form["printersInfoContent"];

                if (string.IsNullOrEmpty(printersInfo) == false)
                    printersInfo = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(printersInfo));

                context.Application.Set(sessionID + "printersInfo", printersInfo);

            }
            else if (prType == RequestType.ClientGetWcppVersion)
            {
                //return the WCPP version for the specified Session ID (sid) if any
                bool sidWcppVersion = (context.Application[sessionID + "wcppInstalled"] != null);

                context.Response.ContentType = "text/plain";
                context.Response.Write(sidWcppVersion ? context.Application[sessionID + "wcppInstalled"] : "");

            }
            else if (prType == RequestType.ClientGetInstalledPrinters)
            {
                //return the installed printers for the specified Session ID (sid) if any
                bool sidHasPrinters = (context.Application[sessionID + "printers"] != null);

                context.Response.ContentType = "text/plain";
                context.Response.Write(sidHasPrinters ? context.Application[sessionID + "printers"] : "");

            }
            else if (prType == RequestType.ClientGetInstalledPrintersInfo)
            {
                //return the installed printers with detailed info for the specified Session ID (sid) if any
                bool sidHasPrinters = (context.Application[sessionID + "printersInfo"] != null);

                context.Response.ContentType = "text/plain";
                context.Response.Write(sidHasPrinters ? context.Application[sessionID + "printersInfo"] : "");

            }

        }
        catch (Exception ex)
        {
            context.Response.StatusCode = 500;
            context.Response.ContentType = "text/plain";
            context.Response.Write(ex.Message + " - " + ex.StackTrace);
        }



    }

    public bool IsReusable {
        get {
            return false;
        }
    }

}
VB

Imports System
Imports System.Web

Imports Neodynamic.SDK.Web


Public Class WebClientPrintAPI : Implements IHttpHandler

    '*********************************
    ' IMPORTANT NOTE 
    ' In this sample we store users related stuff (like
    ' the list of printers and whether they have the WCPP 
    ' client utility installed) in the Application cache
    ' object part of ASP.NET BUT you can change it to 
    ' another different storage (like a DB or file server)!
    ' which will be required in Load Balacing scenarios
    '*********************************

    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        'get session ID
        Dim sessionID As String = ""
        If (context.Request("sid") IsNot Nothing) Then
            sessionID = context.Request("sid")
        End If

        'get Query String
        Dim queryString As String = context.Request.Url.Query

        Try
            'Determine and get the Type of Request 
            Dim prType As RequestType = WebClientPrint.GetProcessRequestType(queryString)

            If prType = RequestType.GenPrintScript OrElse prType = RequestType.GenWcppDetectScript Then
                'Let WebClientPrint to generate the requested script
                Dim script As Byte() = WebClientPrint.GenerateScript(context.Request.Url.AbsoluteUri.Replace(queryString, ""), queryString)

                context.Response.ContentType = "text/javascript"
                context.Response.BinaryWrite(script)
            ElseIf prType = RequestType.ClientSetWcppVersion Then
                'This request is a ping from the WCPP utility
                'so store the session ID indicating this user has the WCPP installed
                'also store the WCPP Version if available
                Dim wcppVersion As String = context.Request("wcppVer")
                If String.IsNullOrEmpty(wcppVersion) Then
                    wcppVersion = "1.0.0.0"
                End If

                context.Application.Set(sessionID & "wcppInstalled", wcppVersion)
            ElseIf prType = RequestType.ClientSetInstalledPrinters Then
                'WCPP Utility is sending the installed printers at client side
                'so store this info with the specified session ID
                Dim printers As String = context.Request("printers")
                If Not String.IsNullOrEmpty(printers) Then
                    printers = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(printers))
                End If

                context.Application.Set(sessionID & "printers", printers)

            ElseIf prType = RequestType.ClientSetInstalledPrintersInfo Then
                'WCPP Utility is sending the installed printers at client side
                'so store this info with the specified session ID
                'Printers Info is in JSON format
                Dim printersInfo As String = context.Request.Form("printersInfoContent")
                If Not String.IsNullOrEmpty(printersInfo) Then
                    printersInfo = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(printersInfo))
                End If

                context.Application.Set(sessionID & "printersInfo", printersInfo)

            ElseIf prType = RequestType.ClientGetWcppVersion Then
                'return the WCPP version for the specified Session ID (sid) if any
                Dim sidWcppVersion As Boolean = (context.Application(sessionID & "wcppInstalled") IsNot Nothing)

                context.Response.ContentType = "text/plain"
                If (sidWcppVersion) Then
                    context.Response.Write(context.Application(sessionID & "wcppInstalled").ToString())
                End If

            ElseIf prType = RequestType.ClientGetInstalledPrinters Then
                'return the installed printers for the specified Session ID (sid) if any
                Dim sidHasPrinters As Boolean = (context.Application(sessionID & "printers") IsNot Nothing)

                context.Response.ContentType = "text/plain"

                If (sidHasPrinters) Then
                    context.Response.Write(context.Application(sessionID & "printers").ToString())
                End If

            ElseIf prType = RequestType.ClientGetInstalledPrintersInfo Then
                'return the installed printers with detailed info for the specified Session ID (sid) if any
                Dim sidHasPrinters As Boolean = (context.Application(sessionID & "printersInfo") IsNot Nothing)

                context.Response.ContentType = "text/plain"

                If (sidHasPrinters) Then
                    context.Response.Write(context.Application(sessionID & "printersInfo").ToString())
                End If
            End If
        Catch ex As Exception
            context.Response.StatusCode = 500
            context.Response.ContentType = "text/plain"
            context.Response.Write(ex.Message + " - " + ex.StackTrace)
        End Try



    End Sub


    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

End Class

Registering the WebClientPrint Script

For ASP.NET MVC Projects

In the View page where the user will perform the printing action e.g. through a button, hyperlink/anchor, script function, etc.; you must register WebClientPrint script.

Suppose you have a Controller class named DemoPrintCommandsController with a method called PrintCommands which generates and returns a ClientPrintJob object, then in the View where you allow users to print, the following code needs to be added inside the <body> tag:

IMPORTANT: Remember to add a link to jQuery 1.4.1+ in the View where you are going to use WebClientPrint script code.


@* Register the WebClientPrint script code. The param is the URL for the PrintCommands method in the DemoPrintCommandsController. *@

@Html.Raw(Neodynamic.SDK.Web.WebClientPrint.CreateScript(Url.Action("ProcessRequest", "WebClientPrintAPI", null, HttpContext.Current.Request.Url.Scheme), Url.Action("PrintCommands", "DemoPrintCommands", null, HttpContext.Current.Request.Url.Scheme), HttpContext.Current.Session.SessionID)))

This must be done once in your View and it will allow you to use the jsWebClientPrint (a javascript object) later on for starting the printing process or getting the list of installed client printers from the View.

For ASP.NET WebForms Projects

In the WebForm page where the user will perform the printing action e.g. through a button, hyperlink/anchor, script function, etc.; you must register WebClientPrint script.

Suppose you have a Generic Handler class named DemoPrintCommands which generates and returns a ClientPrintJob object, then in the WebForm page where you allow users to print, the following code needs to be added inside the <body> tag:

IMPORTANT: Remember to add a link to jQuery 1.4.1+ in the WebForm where you are going to use WebClientPrint script code.


<%-- Register the WebClientPrint script code --%>

<%=Neodynamic.SDK.Web.WebClientPrint.CreateScript(HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Host + ":" + HttpContext.Current.Request.Url.Port + "/WebClientPrintAPI.ashx", HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Host + ":" + HttpContext.Current.Request.Url.Port + "/DemoPrintCommandsHandler.ashx", HttpContext.Current.Session.SessionID)%>

This must be done once in your WebForm and it will allow you to use the jsWebClientPrint (a javascript object) later on for starting the printing process or getting the list of installed client printers from the View.

Printing by using jsWebClientPrint

jsWebClientPrint is the javascript object that you will use to launch the WCPP utility at the client machine.

Before trying to use it, you must ensure you have done what is stated in the Creating the WebClientPrintAPI Class and Registering the WebClientPrint Script topics.

The jsWebClientPrint object features a print() function that you can invoke from HTML or javascript code. The print() function is the one which will launch the WCPP utility at the client machine so it can process the ClientPrintJob generated from your ASP.NET website.

You can pass to the print() function any number of useful data/parameters that you might need to analyze in the method of your Controller class that generates the ClientPrintJob objects. For instance, in our sample code, you will find a javascript code that looks like the following:

HTML/JS
<a onclick="javascript:jsWebClientPrint.print('useDefaultPrinter=' + $('#useDefaultPrinter').attr('checked') + '&printerName=' + $('#installedPrinterName').val() + '&filetype=' + $('#ddlFileType').val());">Print File...</a>

The data/parameters are expressed in the same way as it's done with the Query String and you can gather them from your Controller or Generic Handler class.

Get Installed Printers

jsWebClientPrint allows you to get the list of installed printers available at the client machine by using the getPrinters() function. By "installed printers" it means the printers that are listed and installed under Windows, Linux or Mac OS.

Here's a simple code about how to use this feature. The code has an HTML button that when clicked, it invokes the getPrinters() function. There's also an HTML select element that will be filled with the installed printers if the code on getting the printers successes.

HTML/JS
<input type="button" value="Load Installed Printers..." onclick="javascript:jsWebClientPrint.getPrinters();" />
<br />
<select id="installedPrintersList"></select>

And here is the javascript code to handle the installed printers:

The variable named as wcppGetPrintersTimeout_ms holds how much time (in milliseconds) the script code needs to wait for the installed printers list sent by WCPP from the client side to your website. The variable named as wcppGetPrintersTimeoutStep_ms specifies the period of time after which the script code will request the list of installed printers to the server. In the sample code below, we set a timeout to 10000 ms (i.e. 10 seconds) with a timeout step of 500 ms but you can change it to whatever you want.

HTML/JS
<script type="text/javascript">

var wcppGetPrintersTimeout_ms = 10000; //10 sec
var wcppGetPrintersTimeoutStep_ms = 500; //0.5 sec

function wcpGetPrintersOnSuccess(){
    // Display client installed printers
    if(arguments[0].length > 0){
        var p=arguments[0].split("|");
        var options = '';
        for (var i = 0; i < p.length; i++) {
            options += '<option>' + p[i] + '</option>';
        }
        $('#installedPrintersList').html(options);
        $('#installedPrintersList').focus();                                        
    }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>

Get Installed Printers with detailed info

jsWebClientPrint also allows you to get the list of installed printers available at the client machine with further details about them by using the getPrintersInfo() function. In addition to the printers name, you can also get info like Supported Trays and Papers, Port name, Vertical and Horizontal Resolution, whether the printer is connected, shared, default, local, network and more!

In the source code of the WebClientPrint Sample Website at github, you will find a complete sample source code using this feature.

Detecting whether WCPP is installed at the client machine

The WCPP utility (that the user must have it installed) is a key component of the WebClientPrint solution. So, it is very important you can detect somehow whether the WCPP is already installed at the client machine from your ASP.NET website. In the source code of the WebClientPrint Sample Website at github, you will find a complete sample source code using the detecting technique. However, here are the basic steps involved in this task.

Registering the WCPP detection Script

First of all, be sure you have already done the stated in the Creating the WebClientPrintAPI Class topic. After that, you have to add a simple line of code in the ASP.NET HTML markup code of your View page or WebForm. This View page or WebForm is the one you will be using for detecting whether the user has the WCPP installed or not. It should be the initial page the user should visit before trying to go to the page where you provide the WebClientPrint functionality.

So, open the View page and add the following line of code inside the HTML :

IMPORTANT: Remember to add a link to jQuery 1.4.1+ in the View where you are going to use WCPP Detection script code.

For ASP.NET MVC Projects


@* WCPP detection script *@

@Html.Raw(Neodynamic.SDK.Web.WebClientPrint.CreateWcppDetectionScript(Url.Action("ProcessRequest", "WebClientPrintAPI", null, HttpContext.Current.Request.Url.Scheme), HttpContext.Current.Session.SessionID))

For ASP.NET WebForms Projects


<%-- WCPP detection script code --%>

<%=Neodynamic.SDK.Web.WebClientPrint.CreateWcppDetectionScript(HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Host + ":" + HttpContext.Current.Request.Url.Port + "/WebClientPrintAPI.ashx", HttpContext.Current.Session.SessionID)%>

Handling the WCPP detection with JavaScript

Once you've registered the WCPP detection script in your View page or WebForm, then you can handle the detection result i.e. success or failure and act according to it. You have to write javascript code inside two special functions for handling the detection result. Those functions are named as wcppDetectOnSuccess() and wcppDetectOnFailure()

So, in the View page or WebForm you are using for "WCPP detection", you should add a javascript code like the following:

The variable named as wcppPingTimeout_ms holds how much time (in milliseconds) the detection script needs to wait for a ping from the WCPP at the client side to your website. In the sample code below, we set it to 10000 ms (i.e. 10 seconds) but you can change it to whatever you want.

HTML/JS
<script type="text/javascript">

var wcppPingTimeout_ms = 10000; //10 sec
var wcppPingTimeoutStep_ms = 500; //0.5 sec

function wcppDetectOnSuccess(){
    //WCPP utility is installed at the client side
    //redirect to WebClientPrint sample page

    //TIP! You can get the WCPP Version installed through arguments[0]

    window.location.href = "URL_TO_SAMPLE_PAGE";

}

function wcppDetectOnFailure() {
    //It seems WCPP is not installed at the client side
    //kindly ask the user to install it

    PROVIDE_DOWNLOAD_LINK_TO_WCPP_INSTALLER

}      

</script>

Sample Project & Online Demo

  • Try the WebClientPrint Solution through our Online Demo
  • Look at the source code of the WebClientPrint Sample Website at github
Back to top Copyright © 2003- Neodynamic SRL
http://www.neodynamic.com