Printing from an ASP.NET page

B

Brett

I have an ASP.NET page that displays work orders in a GridView. In that
GridView is a checkbox column. When the user clicks a "Print" button, I
create a report, using the .NET Framework printing classes, for each of the
checked rows in the GridView. This works fine in the Visual Studio 2005
development environment on localhost. But, when I move the page to the web
server, I get the error "Settings to access printer
'\\ServerName\PrinterName' are not valid." (See below.) I get the same
error if I try this while logged into the server, but I can successfully
print a test page from the server.



This printer is installed on the server and is the default printer. The
server is running Windows Server 2003 R2 Service Pack 2, IIS 6 and ASP.NET
2.0.50727.0. Is there any way that I can have this report print when the
page is hosted on the web server? Thank you!

Settings to access printer '\\COLUMBIA\IT Hallway FS-3820N KX' are not
valid.
Description: An unhandled exception occurred during the execution of the
current web request. Please review the stack trace for more information
about the error and where it originated in the code.

Exception Details: System.Drawing.Printing.InvalidPrinterException: Settings
to access printer '\\COLUMBIA\IT Hallway FS-3820N KX' are not valid.

Source Error:

Line 194:Line 195: PrintDoc.Print()Line 196:
PrintDoc.Dispose()Line 197: End Sub



Source File: C:\Inetpub\wwwroot\MaintenanceManager\WorkOrders.aspx.vb
Line: 195

Stack Trace:

[InvalidPrinterException: Settings to access printer '\\COLUMBIA\IT Hallway
FS-3820N KX' are not valid.]
System.Drawing.Printing.PrinterSettings.GetHdevmodeInternal() +123451
System.Drawing.Printing.PrinterSettings.GetHdevmode(PageSettings
pageSettings) +48
System.Drawing.Printing.PrintController.OnStartPrint(PrintDocument document,
PrintEventArgs e) +81
System.Windows.Forms.PrintControllerWithStatusDialog.OnStartPrint(PrintDocument
document, PrintEventArgs e) +33
System.Drawing.Printing.PrintController.Print(PrintDocument document) +201
System.Drawing.Printing.PrintDocument.Print() +111
_Default.PrintWorkOrder() in
C:\Inetpub\wwwroot\MaintenanceManager\WorkOrders.aspx.vb:195
_Default.btnPrint_Click(Object sender, EventArgs e) in
C:\Inetpub\wwwroot\MaintenanceManager\WorkOrders.aspx.vb:180
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +105
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
+107
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String
eventArgument) +7
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl,
String eventArgument) +11
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint,
Boolean includeStagesAfterAsyncPoint) +1746
 
N

Nathan Sokalski

Are you creating a web or desktop application? I notice that the Stack Trace
contains the following:

System.Windows.Forms.PrintControllerWithStatusDialog.OnStartPrint(PrintDocument
document, PrintEventArgs e) +33

The System.Windows.Forms namespace is never used in an ASP.NET application.
If you want to print an ASP.NET page, you will need to use the JavaScript
window.print() method. If you want to have a printable version generated
when the user clicks the button or link to print, I would suggest the
following:

1. Create another page that generates the appropriate report (probably using
a querystring)
2. In the link to this page, be sure to include target="_blank" so that the
page opens in a new window
3. Use the following for the body tag of the new page, which will print the
page and then close it:

<body onload="window.print();window.close();">

This technique will allow the user to bring up their browser's print dialog,
close the window, and return to the previous page with the click of a single
button or link. If you are trying to make a desktop application, well, then,
you are posting to the wrong newsgroup. Good Luck!
--
Nathan Sokalski
(e-mail address removed)
http://www.nathansokalski.com/

Brett said:
I have an ASP.NET page that displays work orders in a GridView. In that
GridView is a checkbox column. When the user clicks a "Print" button, I
create a report, using the .NET Framework printing classes, for each of the
checked rows in the GridView. This works fine in the Visual Studio 2005
development environment on localhost. But, when I move the page to the web
server, I get the error "Settings to access printer
'\\ServerName\PrinterName' are not valid." (See below.) I get the same
error if I try this while logged into the server, but I can successfully
print a test page from the server.



This printer is installed on the server and is the default printer. The
server is running Windows Server 2003 R2 Service Pack 2, IIS 6 and ASP.NET
2.0.50727.0. Is there any way that I can have this report print when the
page is hosted on the web server? Thank you!

Settings to access printer '\\COLUMBIA\IT Hallway FS-3820N KX' are not
valid.
Description: An unhandled exception occurred during the execution of the
current web request. Please review the stack trace for more information
about the error and where it originated in the code.

Exception Details: System.Drawing.Printing.InvalidPrinterException:
Settings to access printer '\\COLUMBIA\IT Hallway FS-3820N KX' are not
valid.

Source Error:

Line 194:Line 195: PrintDoc.Print()Line 196: PrintDoc.Dispose()Line
197: End Sub



Source File: C:\Inetpub\wwwroot\MaintenanceManager\WorkOrders.aspx.vb
Line: 195

Stack Trace:

[InvalidPrinterException: Settings to access printer '\\COLUMBIA\IT
Hallway FS-3820N KX' are not valid.]
System.Drawing.Printing.PrinterSettings.GetHdevmodeInternal() +123451
System.Drawing.Printing.PrinterSettings.GetHdevmode(PageSettings
pageSettings) +48
System.Drawing.Printing.PrintController.OnStartPrint(PrintDocument
document, PrintEventArgs e) +81
System.Windows.Forms.PrintControllerWithStatusDialog.OnStartPrint(PrintDocument
document, PrintEventArgs e) +33
System.Drawing.Printing.PrintController.Print(PrintDocument document) +201
System.Drawing.Printing.PrintDocument.Print() +111
_Default.PrintWorkOrder() in
C:\Inetpub\wwwroot\MaintenanceManager\WorkOrders.aspx.vb:195
_Default.btnPrint_Click(Object sender, EventArgs e) in
C:\Inetpub\wwwroot\MaintenanceManager\WorkOrders.aspx.vb:180
System.Web.UI.WebControls.Button.OnClick(EventArgs e) +105
System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
+107
System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String
eventArgument) +7
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl,
String eventArgument) +11
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1746
 
S

Steven Cheng [MSFT]

Hi Brett,

As for the report printing, do you want it to print at the client-side
machine or server-side machine. As Nathan has mentioned, ASP.NET web
application is totally running separate from client-side browser
environment. for printing, you have the following different choice:

1. Let page opened in client-side webbrowser and user click browser's
"print" menu to print. Or you can use javascript "window.print()" to print
the current page. However, our server-side web application doesn't have
much control on the client-side printing setting or printers

2. You only want to print at server-side, then, you can use printing code
in your asp.net server-side code , such code will only use printers at
ASP.NET web server, and the client user will never see what happed for the
printers at server-side.

The reason why you'll see some different behavior(the client user can also
see server-side printing code work) when using visual studo test server is
as below:

** visual studio test server is a winform application which runs on local
machine(under the current logon user).

** so if you use any desktop application code(such as winform code) in
asp.net pages which hosted in visual studio test server, it will also be
visible

** however, if you deploy the ASP.NET application to IIS, that's totally
different. IIS worker process runs under a non-visible user session and
under an different non-interactive user account.

If you have anything unclear on this, please feel free to post here.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
 
B

Brett

Thank you, Steven and Nathan, for your quick response!

This is a web application and will print to a network printer. Ideally, it
would print from the client-side, but server-side will be OK, because all
users are likely to use the same printer.

The application has been using the javascript "window.print" until now, but
the users would like to be able to select multiple rows from the GridView
and print them all with one click. Is this possible?

Thanks!
Brett
 
N

Nathan Sokalski

If you want it to print specific rows, do something like add a checkbox to
each row and then generate a page using some variation of my original
suggestion.
 
S

Steven Cheng [MSFT]

Hi Brett,

Thanks for your reply.

For the new question you mentioned. I would suggest you consider the
following approach:

1. One the original page (with Gridview), provide checkbox to let user
choose the rows to print

2. When the user click a print button, the page will postback, and you can
find all the selected rows(by looping the gridview to check checkbox
values) and redirect the user to a new page which will only display those
selected rows.

thus, on the new page the user can print what they exactly want. Just an
idea of generate a print version. How do you think?

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
--------------------
Subject: Re: Printing from an ASP.NET page
Date: Fri, 11 Jul 2008 09:11:49 -0400
 
B

Brett

The problem with <body onload="window.print();window.close();"> is that the
browser still prompts the user about closing the window, so it doesn't save
the user any keystrokes. It is just as easy for them to close the window or
go to the previous page themselves. When selecting multiple reports, the
users will not like having to confirm closing the window for each report.
An alternative to "window.close" might be "history.go(-1)" but that does not
wait for the user to print before returning to the previous page.

Your latest suggestion is close, but I need a separate page for each
selected record, showing additional data (from the same table) that is not
shown in the GridView.

I have also tried using a ReportViewer control on the page, but I had
problems with that, too, including a persistent "parameter is missing a
value" error. Do you think the use of ReportViewer may have some potential?

The original server-side printing, using .NET printing methods works so
nicely in the Visual Studio test environment, it is disappointing that it
cannot be used on the real web server.
 
S

Steven Cheng [MSFT]

Hi Brett,

Thanks for your further reply.

As for ReportViewer, I think the printing functionality is also quite
limited since you cannot control the printing setting in code(but let the
user choose when click print button).

For server-side printing, it is not completely unavailable, but no
recommended. You can try the following:

1. first check your server-side printing code(which use some winform
printing code) to ensure that the one will not require any interactive
operations such as prompt dialog box that need a user to respond. All the
code should be able to finish programmtically without UI.

2. You can try changing your ASP.NET application's worker process
account(for IIS6 it is the application pool identity). Switch it to an
interactive user account such a domain user account or local logon user so
that it can access the certain printers. Or you can consider using
impersonate at runtime to let your application running under a certain user
account.

Here are some information about IIS worker process identity and impersonate
in ASP.NET

#How To: Use Impersonation and Delegation in ASP.NET 2.0
http://msdn.microsoft.com/en-us/library/ms998351.aspx

#How to implement impersonation in an ASP.NET application
http://support.microsoft.com/kb/306158

#IIS Worker processes & windowstation/desktops
http://blogs.msdn.com/nicd/archive/2007/05/10/iis6-winstation-desktop-settin
gs.aspx

BTW, if the printing task is a frequently used functionality on your
webserver, I suggest you also consider the following approach:

* create a separate winform application running on the server which will
receive printer request(with necessary data) and do the printing task to
certain printers on the server

* Your ASP.NET application will always send printing task request to that
winform application. the communication channel maybe any existing remoting
approach such as : remoting, webservice, WCF, MSMQ....

How do you think?

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.




--------------------
<e#[email protected]>
Subject: Re: Printing from an ASP.NET page
Date: Mon, 14 Jul 2008 16:49:43 -0400
 
B

Brett

Thank you for your continuing support on this.

For the server-side printing approach, I tried changing the worker process
account to an interactive user account, but I still got the same message
that "Settings to access printer '\\servername\printername' are not valid."
To do this, I:
- created a new application pool
- added a local account on the web server
- added the new account to the IIS_WPG group
- made the new account the worker account for the new application pool
- made the new application pool the app pool for my application
- logged onto the web server with the new account and successfully tested
printing from that account

Since this is a network printer, I then tried changing the worker process
account to a network account, but I continued to get the same error message.
Do you have any other ideas what may cause this error?

For the ReportViewer approach, I got it to create the report, which the user
can export to PDF and then print. That's a couple extra steps for the user,
and the overall functionality of ReportViewer is restrictive, when compared
to writing your own printing code.
 
S

Steven Cheng [MSFT]

Thanks for your reply Brett,

Here I found a forum thread which mentioned a similar question. For
accessing network printer, you can refer to some points mentioned there:

* if you use a network/domain account, verify whether that account has
correct permission to access the network printer(test the same code, same
account in a desktop app)

* someone also mentioned approach to use some printer port redirection
component or tool to map a local print port to a remote printer

#Access Your Network Printer
http://forums.asp.net/t/587341.aspx

BTW, is it possible that the printing part be separated from the main
ASP.NET application and run it as a desktop one and let ASP.NET send
printing request to it so that the actual report printing is done in the
desktop application.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
 
B

Brett

Yes, I could run the printing part as a Winform application. I'm not sure
how I should implement it. (.NET remoting? Web service?) The
communication between applications would be a new area for me.

I found an article on MSDN that shows how to use a console application to
print a local report without previewing it:
http://msdn.microsoft.com/en-us/library/ms252091(VS.80).aspx
When I ran the console application , it successfully printed the report, but
when I tried to call the console app from the web app, I got
"PrintLocalReport has encountered a problem and needs to close."

Error signature:
EventType : clr20r3 P1 : printlocalreport.exe P2 : 1.0.0.0
P3 : 487e4d71 P4 : mscorlib P5 : 2.0.0.0 P6 : 471ebc5b
P7 : 3404
P8 : d8 P9 : system.io.filenotfoundexception

The following code fails at "Dim p As System.Diagnostics.Process."

Dim filePath As String = Server.MapPath("PrintLocalReport.exe")

Dim info As System.Diagnostics.ProcessStartInfo = New
System.Diagnostics.ProcessStartInfo(filePath, "")

info.UseShellExecute = False

Dim p As System.Diagnostics.Process =
System.Diagnostics.Process.Start(info)

p.Start()


I don't know what file was not found. I did a "File.exists(filepath)" and
it returned "True"
 
S

Steven Cheng [MSFT]

Thanks for your reply Brett,

Yes, webservice or even simple network socket programming is ok(or if you
can use .net 3.0, WCF will be much more convenient). Also, if you are
familar with MSMQ programming, you can consider make each print request as
a MSMQ message and send to a message queue, and your target winform
application constantly pick messages from queue and perform printing.

For the console application, do not call it from your ASP.NET application,
that way, you are doing the samething as you try calling winform printing
code in asp.net application since that will make the consile running in the
same user context of the ASP.NET web applicaction. You should run the
console or winform application from a logon user context and let the
asp.net application communicate it via some remote communication methods.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
<e#[email protected]>
<OC0d#[email protected]>
<[email protected]>
<#[email protected]>
<[email protected]>
 
B

Brett

I don't know anything about inter-process communication, and I can't really
afford to spend more time at this point, experimenting with every possible
method to see which, if any, will actually work for me. I cannot believe
that simply printing a report from a web application could be so difficult.

In all my research, I found an article that said that the print button was
available for local reports on the Visual Studio 2008 ReportViewer. So, I
upgraded my project to VS08. Lo and behold, there was the print button.
Works like a charm...in the development environment. So, I copied the web
form and the code-behind file to the server. I also installed the
redistributable for the Report Viewer on the web server. I ran the
application on the server, and I got the parser error shown below. I then
added this line to the web.config:
<add verb="*" path="Reserved.ReportViewerWebControl.axd" type =
"Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms,
Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />

Then, I got the compilation error below:

Compilation Error
Description: An error occurred during the compilation of a resource required
to service this request. Please review the following specific error details
and modify your source code appropriately.
Compiler Error Message: BC30560: 'ReportDataSource' is ambiguous in the
namespace 'Microsoft.Reporting.WebForms'.
Source Error:
Line 241:
Line 242: 'Associate thisDataSet (now loaded with the stored
procedure result) with the ReportViewer datasource
Line 243: Dim datasource As New
ReportDataSource("DataSet1_SelectWorkOrder", thisDataSet.Tables(0))

This looks like an error in my code, but it had worked in the development
environment.




Parser Error
Description: An error occurred during the parsing of a resource required to
service this request. Please review the following specific parse error
details and modify your source file appropriately.

Parser Error Message: Could not load file or assembly
'Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system
cannot find the file specified.

Source Error:

Line 2: EnableEventValidation = "false" Inherits="_Default"
Title="Maintenance Manager: Work Orders" Trace="false" %>
Line 3:
Line 4: <%@ Register Assembly="Microsoft.ReportViewer.WebForms,
Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
Line 5: Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
Line 6:

Source File: /MaintenanceManager/WorkOrdersvs08.aspx Line: 4

Assembly Load Trace: The following information can be helpful to determine
why the assembly 'Microsoft.ReportViewer.WebForms, Version=9.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' could not be loaded.

WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value
[HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind
failure logging.
To turn this feature off, remove the registry value
[HKLM\Software\Microsoft\Fusion!EnableLog].



--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.1433;
ASP.NET Version:2.0.50727.1433
 
S

Steven Cheng [MSFT]

Thanks for your reply Brett,

Per the error message you provided, it indicate that the runtime cannot
locate the reportviewer control's assembly.As for ReportViewer controls(the
winform and webform ones), they're part of the components shipped with
Visual Studio instead of .net framework:

#ReportViewer Controls (Visual Studio)
http://msdn.microsoft.com/en-us/library/ms251671.aspx

therefore, they're not included in .net framework built-in components. For
a production server which only have .net framework installed(but no visual
studio), it hasn't ReportViewer controls. For such case, you need to deploy
the reportviewer control to the server first.

#Deploying Reports and ReportViewer Controls
http://msdn.microsoft.com/en-us/library/ms251723.aspx

The redistributable package of reportviewer is included in visual studio,
you can also download it and install it on the server.
#Microsoft Report Viewer Redistributable 2008
http://www.microsoft.com/downloads/details.aspx?FamilyID=cc96c246-61e5-4d9e-
bb5f-416d75a1b9ef&DisplayLang=en

Sincerely,

Steven Cheng
Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.





--------------------
 
B

Brett

After trying several different approaches, it turns out that upgrading the
project to Visual Studio 2008 and using the newer ReportViewer was the
solution for me. Thanks for your efforts.

Brett
 
J

jt007superman jt007superman

Hello there, I think we are making this much more difficult than it is.

As I understand, you have a page which has a gridview of records
containing some, but not all, record information that already contains a
list of checkboxes next to each record and a print button.

What you would need to do is:
1) Click the Print button with some records selected.

2) Have JS handler to determine checked values and send
the keys in a querystring to another report page.

3) On the page generated by report page wrap records with
a div using CSS style PageBreak-after:always;

Viola, the page will have all records and the records will print on
individual pages.
 
S

Steven Cheng [MSFT]

Thanks for your reply Brett,

I'm glad that you've got it working. If there is anything else we can help
in the future, please feel free to post here.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top