The WebClientPrint server component

In this section


Overview

The WebClientPrint is a client-server solution. The server-side component is a .NET managed-code assembly (Neodynamic.SDK.WebClientPrint.dll) which is used in your ASP.NET website to generate "Client Print Jobs".

A Client Print Job allows you to specify:

The WebClientPrint server component requires:


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 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 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:

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:

Visual Basic

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"


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";

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:

Visual Basic

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"


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";

WindowsDriverPrinter

The WindowsDriverPrinter 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 OS. Those printers are generally installed by using a Windows driver provided by the manufacturer.

NOTE
For Raw printing, installing the "Generic / Text Only" driver that comes with Windows 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:

Visual Basic

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 printer's name on the client machine
cpj.ClientPrinter = New WindowsDriverPrinter("MyLocalPrinter")

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


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 WindowsDriverPrinter("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 WindowsDriverPrinter 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:

Visual Basic

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 WindowsDriverPrinter("\\anotherPC\CoolBrandPrinter")

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


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 WindowsDriverPrinter("\\anotherPC\CoolBrandPrinter");

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

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. Here is a snippet code of how to use this option:

Visual Basic

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"


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";

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. Here is a snippet code of how to use this option:

Visual Basic

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, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, 8, System.IO.Ports.Handshake.XOnXOff)

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


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, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, 8, System.IO.Ports.Handshake.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. Here is a snippet code of how to use this option:

Visual Basic

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"


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";

Printer Commands

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 features non-printable or non-human-readable characters in it 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:

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

Visual Basic

'set the commands to send to the printer
cpj.PrinterCommands = "&H1B C &H00 5"

'enable Hex notation for commands
cpj.FormatHexValues = True


C#

//set the commands to send to the printer
cpj.PrinterCommands = "0x1B C 0x00 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 a PRN file.

Visual Basic

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


C#

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

Sending the ClientPrintJob to the client

After you create a ClientPrintJob object, set its main properties like the target ClientPrinter and the PrinterCommands you want to print; then the final step is to send the ClientPrintJob to the client machine from ASP.NET. To do this, you just invoke the SendToClient method of the ClientPrintJob class specifying a HTTP Response object. Here is a snippet of how you should do this:

Visual Basic

'Send ClientPrintJob back to the client so it can be processed by the WCPP
cpj.SendToClient(System.Web.HttpContext.Current.Response)


C#

//Send ClientPrintJob back to the client so it can be processed by the WCPP
cpj.SendToClient(System.Web.HttpContext.Current.Response);

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 web page. The WebClientPrint class provides you with all the needed to perform this task without efforts at all.

Registering the WebClientPrint HTTP Handler in the web.config

All the scripts of WebClientPrint require you to register the wcp.axd HTTP Handler in your web.config file before trying to use them. Depending on the IIS version running on your web server, you might need to register it under <httpHandlers> of <system.web> (for IIS v6) or under <handlers> of <system.webServer> (for IIS 7 or greater). Here are the entries you need to add to your web.config file for either case:

<configuration>
...
<system.web>
    <httpHandlers>
      <add verb="*" path="wcp.axd" type="Neodynamic.SDK.Web.WebClientPrint, Neodynamic.SDK.WebClientPrint"/>
    </httpHandlers>
</system.web>

<system.webServer>
    <handlers>      
      <add name="WebClientPrint" verb="*" path="wcp.axd" type="Neodynamic.SDK.Web.WebClientPrint, Neodynamic.SDK.WebClientPrint"/>
    </handlers>
</system.webServer>
...
</configuration>

Registering the WebClientPrint Script

The first step before scripting to WebClientPrint is to add a simple line of code in the ASP.NET HTML markup code of your web page. This must be done once in your page so you can use the jsWebClientPrint (a javascript object) later on. The page is the one from where the user will perform the printing action e.g. through a button, hyperlink, script function, etc.

So, open the ASPX page and add the following line of code inside the HTML <body>:


NOTE
Remember to add a link to jQuery 1.4.1 or greater in the page where you are going to use WebClientPrint script code.



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 "Registering the WebClientPrint Script" topic.

The jsWebClientPrint object features a print() method that you can invoke from HTML or javascript code. The print() method is the one which invokes 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() method any number of useful data/parameters that you might need to analyze in the method of your server class that generates the ClientPrintJob objects. In our sample code demos, we usually pass to the print() method the user's Session ID that we use then to determine what kind of ClientPrintJob needs to be generated. So, in our sample code demos, you will find a javascript code that looks like the following:


NOTE
If you are going to use Session.SessionID in your project, there are a couple of things to keep in mind. In the Session_Start event of the Global.asax file of your website you should do the following:
  1. To avoid the SessionID changes on every postback, you should add some value to the Session object. In our sample code, we used this: Session.Add("wcp", "started")
  2. To fix the exception: "Session state has created a session id, but cannot save it because the response was already flushed by the application." (only for MVC projects), add this line Dim sessionId As String = Session.SessionID (for VB) or this string sessionId = Session.SessionID; (for C#)



Commanding the WCPP through jsWebClientPrint

In addition to the print() method, the jsWebClientPrint object features the send() method which allows you to send to the WCPP installed at the client side some useful commands or parameters. The following is the list of supported commands:


How to detect if WCPP is installed at the client machine

The WCPP utility that the user needs to have it installed is a key component of the WebClientPrint solution. So, it is very important you can detect somehow if the WCPP is already installed at the client machine from your ASP.NET website. In the sample code projects that are installed with the WebClientPrint package, 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 registered the wcp.axd HTTP Handler. After that is done, you have to add a simple line of code in the ASP.NET HTML markup code of your web page. The page is the one you will be using for detecting if 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 ASPX page and add the following line of code inside the HTML <body>:


NOTE
Remember to add a link to jQuery 1.4.1 or greater in the page.



Handling the WCPP detection with JavaScript

When you register the WCPP detection script in your page, 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 page you are using for "WCPP detection", you should add a javascript code like the following:


<script type="text/javascript">
       
    var wcppPingDelay_ms = 10000; //10 sec

    function wcppDetectOnSuccess(){
        //WCPP utility is installed at the client side
        //redirect to WebClientPrint sample page
        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>

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