我有一个长期运行的WCF服务,托管在IIS中,无需任何用户交互即可处理打印。循环完1000个打印作业大约2个小时后,WCF服务似乎就要死了。我跟踪的日志文件表示最后一个打印作业已发送到打印机,但它永远不会返回成功也不会失败(同样,根据日志文件)。
从日志文件中,通常会说:
2015-12-17 19:00:23,673 [27] INFO 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] INFO 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);
}
}
答案 0 :(得分:0)
这是在Windows事件日志中:
进程标识为“3236”的工作进程为应用程序池提供服务 由于不活动,'testws.mydomain.ca'已关闭。应用程序池 超时配置设置为20分钟。一个新的工人流程 将在需要时启动。
因此,IIS似乎认为有20分钟不活动,因为WCF服务是异步调用的。该过程正在消失,但IIS决定在流程运行过程中回收应用程序池。
我根据这个更改了应用程序池中IIS的设置: https://serverfault.com/questions/333907/what-should-i-do-to-make-sure-that-iis-does-not-recycle-my-application
答案 1 :(得分:0)
我建议检查打印方法的操作合同。我已经看到,当未设置isOneWay属性或在void方法上将其设置为false时,WCF服务失败。试试这样的事情
[OperationContract(IsOneWay=true)]
public void PrintDocumentWithSettings(PageSettings settings, PrinterSettings settings);