C#打印问题与system.Drawing.Printing from #web API

C# Printing problem with system.Drawing.Printing from #web API


问题
 Hello everyone,
    
 I have a situation to print PDF document as a batch from Web API. 
 And I have used System.Drawing.Printing Library to print them.
    
 I have noticed the ‘Caution’ mentioned on Microsoft site (https://docs.microsoft.com/en-us/dotnet/api/system.drawing.printing?view=net-5.0) as below.
    
 Specifications:
 1)    We are using network printers.
 2)    Windows server 2016 standard.
    
 Caution:
 Classes within the System.Drawing.Printing namespace are not supported for use within a Windows service or ASP.NET application or service. 
 Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions.
    
 As mentioned in the caution I am facing some unexpected problems intermittently during print operation as below.
    
 Problems:
 1)    Pages are missing in the PDF documents. Example: Out of 10 pages 5th page is missed.
 2)    Documents are missing, example: out of 100 documents 99/ 95 printed. Some of them is missed. 
    
 Exception occured in PrintPdf method: The handle is invalid System.ComponentModel.Win32Exception (0x80004005): The handle is invalid
    at System.Drawing.Printing.StandardPrintController.OnStartPrint(PrintDocument document, PrintEventArgs e)
    at System.Drawing.Printing.PrintController.Print(PrintDocument document)
    at System.Drawing.Printing.PrintDocument.Print()
    
    
 Code snippet:
    
     using (var document = _pdfDocumentWrapper.Load(stream))
                 {
                     using (var printDocument = _pdfDocumentWrapper.CreatePrinterDocument(document))
                     {
                         var printerName = printerconfiguration;
                         Print(printDocument, printerName);
                     }
                 }
        
     private void Print(PrintDocument printDocument, string printerName)
             {
                                    
                 var printerSettings = new PrinterSettings { PrinterName = printerName };
                 var pageSettings = new PageSettings(printerSettings) { Margins = new Margins(0, 0, 0, 0) };
                 printDocument.PrinterSettings = printerSettings;
                 printDocument.DefaultPageSettings = pageSettings;
                 printDocument.PrintController = new StandardPrintController();
                 printDocument.BeginPrint += PrintDocument_BeginPrint;
                 printDocument.PrintPage += PrintDocument_PrintPage;
                 printDocument.EndPrint += PrintDocument_EndPrint;
                    
                 printDocument.Print();
             }
    
 Any suggestions or alternative approach for the same would be greatly appreciated.

也许你在一个64位的服务器上以32位模式运行c#程序,这导致应用程序以隔离模式运行。根据这个 线程 ,隔离模式导致了这个问题。
打印功能试图连接到一个32位的驱动程序 ,而不是安装的64位的驱动程序,也可能造成这个问题,或者 打印机驱动程序已经过期


答案1

这真的取决于你打算用该打印件做什么。如果你要为用户打印一份实体文件,那么他们如何获得该文件。你的网络服务器可以托管在本地或云端。它可能有也可能没有机会接触到需要它的人附近的打印机。在大多数情况下,更好的解决方案是在客户端进行打印。你可以编写javascript,在客户端可用的打印机上打印一批PDF文件。这样就不需要在服务器端打印了。当然,用户也可以直接打开PDF并从他们的PDF浏览器中打印。

如果你需要打印PDF,以便你可以操作它们,那么就不必费心打印,只需使用一个PDF库,如iText或类似的库,做你的PDF操作。

如果你真的需要将PDF打印到打印机上,那么,忽略打印机无法访问的问题,你会想把这个过程移到带外。在我需要这样做的少数情况下,我们创建了一个简单的控制台应用程序来完成打印工作。该控制台应用程序使用进程任务运行,但它使用一个本地用户的凭证运行,这确保了机器上的本地打印机被使用。当然,这样做性能不好,因为用一个交互式用户启动一个进程会很慢(相对而言)。你也可以创建一个控制台应用程序,托管一个WCF服务(或者如果你使用.NET Core,则直接托管Kestrel),然后与你的API进行通信。控制台应用程序需要在服务器启动时启动,但不应该是一个Windows服务,因为这也不被支持。这种方法有很多问题,但它能起到一点作用。

最后,在我看来,最好的选择是编写一个周期性运行的批处理程序(也许通过计划任务)。API将简单地把打印请求添加到一些共享队列(可能是数据库或消息队列)。批处理程序,当它运行时,将拾取要打印的东西,然后打印它们。如果使用一个数据库,那么处理器可以在完成后更新状态。API将提供一个相应的端点来检查打印的状态,这样用户就可以得到通知(如果相关)。请注意,API不希望等待打印完成,因为它可能比网络请求的时间更长。这就是202 HTTP状态代码的作用--我已经开始处理了,但还没有完成,这里有一些ID,你可以用它来查询以后的完成状态。