Migrating to WebClientPrint 3.0 for ASP.NET MVC & WebForms
Product WebClientPrint for ASP.NET Published 11/26/2016 Updated 11/26/2016 Author Neodynamic
Overview
Due to some new features and customers requests, the brand new WebClientPrint 3.0 for ASP.NET is not backwards compatible with older versions. Please use this article as a general guide to upgrading your server-side code to v3.0
In this article:
- WCPP Client phasing out support for some very old Windows versions
- WCP.AXD HTTP Handler
- WCPP Detection Stuff
- Registering the WebClientPrint Script code generation
- Returning the ClientPrintJob content
A WCPP Client phasing out support for some very old Windows versions
Starting with v3.0, the WCPP Client Utility will not longer support Windows 98, Windows 2000, and Windows ME. So if your client machines are running any of these Windows versions, then you must not migrate to v3.0
B WCP.AXD HTTP Handler
v2.0 requires the following entry in the web.config file of your website:
<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>
Starting with v3.0, this entry is no longer needed and these are the steps to follow up for migrating:
B. 1. REMOVE these entries from your web.config file
B. 2. v3.0 requires you to create a WebClientPrint API file which will be a Controller class in MVC and a Generic Handler ASHX file in WebForms
Create a new Controller and name it WebClientPrintAPIController and then copy/paste the following code:
C#
public class WebClientPrintAPIController : Controller
{
//*********************************
// 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 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.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();
}
}
catch (Exception ex)
{
HttpContext.Response.StatusCode = 500;
HttpContext.Response.ContentType = "text/plain";
HttpContext.Response.Write(ex.Message + " - StackTrace: " + ex.StackTrace);
HttpContext.Response.End();
}
}
}
VB
Public Class WebClientPrintAPIController
Inherits Controller
'*********************************
' 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.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()
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
Create a new Generic Handler and name it WebClientPrintAPI and then copy/paste the following code:
C#
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.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"] : "");
}
}
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
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.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
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
C WCPP Detection Stuff
C. 1. METATAG for Internet Explorer
v2.0 requires the following meta tag in the HEAD section of your webpage.
Neodynamic.SDK.Web.WebClientPrint.GetWcppDetectionMetaTag();
Starting with v3.0, this code is no longer needed so you should REMOVE this from your View or WebForm
C. 2. WCPP Detection Script
v2.0 requires the following code for generating the script code
Neodynamic.SDK.Web.WebClientPrint.CreateWcppDetectionScript();
Starting with v3.0, this must be replaced by the following code:
@* WCPP detection script *@
@Html.Raw(Neodynamic.SDK.Web.WebClientPrint.CreateWcppDetectionScript(Url.Action("ProcessRequest", "WebClientPrintAPI", null, HttpContext.Current.Request.Url.Scheme), HttpContext.Current.Session.SessionID))
<%-- 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)%>
D Registering the WebClientPrint Script code generation
v2.0 requires the following code for generating the script which will allow you to print
Neodynamic.SDK.Web.WebClientPrint.CreateScript();
Starting with v3.0, this new code will be required:
@* Register the WebClientPrint script code. *@
@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)))
<%-- 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)%>
E Returning the ClientPrintJob content
In v2.0 you returned the ClientPrintJob back to the client by using a code like this one:
cpj.SendToClient(Response);
Starting with v3.0, the following code lines will be required:
C#
System.Web.HttpContext.Current.Response.ContentType = "application/octet-stream";
System.Web.HttpContext.Current.Response.BinaryWrite(cpj.GetContent());
System.Web.HttpContext.Current.Response.End();
VB
System.Web.HttpContext.Current.Response.ContentType = "application/octet-stream"
System.Web.HttpContext.Current.Response.BinaryWrite(cpj.GetContent())
System.Web.HttpContext.Current.Response.End()
C#
context.Response.ContentType = "application/octet-stream";
context.Response.BinaryWrite(cpj.GetContent());
context.Response.End();
VB
context.Response.ContentType = "application/octet-stream"
context.Response.BinaryWrite(cpj.GetContent())
context.Response.End()
That's all. Most of the changes in v3.0 are internal and requires you to make minor modifications in your projects which were created for v2.0
As always, do not hesitate to contact our dev team at http://neodynamic.com/support