【发布时间】:2015-12-18 16:15:58
【问题描述】:
我有一个长期运行的 WCF 服务,托管在 IIS 中,无需任何用户交互即可处理打印。在循环 1000 个打印作业大约 2 小时后,WCF 服务似乎死了。我跟踪的日志文件表明最后一个打印作业已发送到打印机,但它从不返回成功或失败(同样,根据日志文件)。
从日志文件中,它通常会说:
2015-12-17 19:00:23,673 [27] 信息 Barn.WCF.SysPrsPrintServer - 发送打印作业... PrintDocumentId=168;PrintSectionId=742;CustomerId=112702;DeliveryAddressId=474984;DocumentName=/SystemProcesses/ Reports/CertificateOfRegistry;PrinterLocation=HB-MFP1;PrinterPaperSource=Cassette 3
2015-12-17 19:00:32,626 [27] INFO Barn.WCF.SysPrsPrintServer - PdfPrintHandler.Print:打印机 HB-MFP1 指示打印作业已完成。
但最后一个日志文件条目是:
2015-12-17 19:00:32,688 [27] 信息 Barn.WCF.SysPrsPrintServer - 发送打印作业... PrintDocumentId=169;PrintSectionId=742;CustomerId=112702;DeliveryAddressId=474984;DocumentName=/SystemProcesses/ Reports/CertificateOfRegistry;PrinterLocation=HB-MFP1;PrinterPaperSource=Cassette 3
您能看出我根本没有收到任何消息是怎么可能的吗? WCF服务是否可能刚刚死掉或IIS回收了应用程序池或类似的东西?所以不用多说,这是我的课:
using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.IO;
using System.Threading;
using log4net;
using Aspose.Pdf.Facades;
namespace Barn.API.Print.PrintHandlers
{
public class PdfPrintHandler
{
private const int LargePdfByteCount = 3000000;
private readonly ILog _log;
private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);
public PdfPrintHandler(ILog log)
{
_log = log;
var license = new Aspose.Pdf.License();
var pathLicense = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "bin\\Aspose.Pdf.lic";
license.SetLicense(pathLicense);
}
/// <summary>
/// Prints the specified stream.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="printerSettings">The printer settings.</param>
/// <param name="pageSettings">The page settings.</param>
/// <param name="timeout">The timeout.</param>
/// <param name="errors"></param>
/// <returns>The status of the print job.</returns>
public PrintJobStatusEnum Print(Stream stream, PrinterSettings printerSettings, PageSettings pageSettings, PrintDocumentModel printJob, int timeout, out List<string> errors)
{
errors = new List<string>();
// Reset the wait handler to make sure the event is not signaled
_resetEvent.Reset();
// Set attributes for printing
var viewer = new PdfViewer
{
AutoResize = true,
AutoRotate = true,
PrintPageDialog = false,
PrintAsImage = false
};
// Add an event listener when print job sent to printer
viewer.EndPrint += ViewerOnEndPrint;
//Print document using printer and page settings
try
{
_log.InfoFormat("Sending Print Job... PrintDocumentId={0};PrintSectionId={1};CustomerId={2};DeliveryAddressId={3};DocumentName={4};PrinterLocation={5};PrinterPaperSource={6}",
printJob.PrintDocumentId,
printJob.PrintSectionId != null ? printJob.PrintSectionId.ToString() : "null",
printJob.CustomerId != null ? printJob.CustomerId.ToString() : "null",
printJob.DeliveryAddressId != null ? printJob.DeliveryAddressId.ToString() : "null",
printJob.DocumentName != null ? printJob.DocumentName : "null",
printJob.PrinterLocation != null ? printJob.PrinterLocation : "null",
pageSettings.PaperSource.SourceName != null ? pageSettings.PaperSource.SourceName : "null");
// Print
if (stream.Length <= LargePdfByteCount)
{
// Bind the stream then print
viewer.BindPdf(stream);
viewer.PrintDocumentWithSettings(pageSettings, printerSettings);
}
else
{
// Use a more efficient printing method with larger documents
viewer.PrintLargePdf(stream, pageSettings, printerSettings);
}
// Block until the event finishes or timeout reached
_resetEvent.WaitOne(TimeSpan.FromMinutes(timeout));
// Check the print status
if (viewer.PrintStatus != null)
{
// An exception was thrown
var ex = viewer.PrintStatus as Exception;
if (ex != null)
{
// Get exception message
_log.Error("PdfPrintHandler.Print: Print Error: " + ex.Message + ex.StackTrace, ex);
errors.Add(ex.Message);
}
return PrintJobStatusEnum.Error;
}
else
{
// No errors were found. Printing job has completed successfully
_log.InfoFormat("PdfPrintHandler.Print: Printer {0} indicates the print job is complete.", printerSettings.PrinterName);
return PrintJobStatusEnum.Printed;
}
}
catch (Exception e)
{
_log.Error("PdfPrintHandler.Print Exception: " + e.Message + e.StackTrace, e);
errors.Add(e.Message);
}
finally
{
viewer.Close();
}
return PrintJobStatusEnum.Error;
}
private void ViewerOnEndPrint(object sender, PrintEventArgs printEventArgs)
{
// Signal the event is finished
_resetEvent.Set();
}
}
}
WCF 服务接口:
using System.ServiceModel;
namespace Barn.WCF
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "ISysPrsPrintServer" in both code and config file together.
[ServiceContract]
public interface ISysPrsPrintServer
{
[OperationContract]
string DoWork(string data);
}
}
【问题讨论】: