长期运行的WCF服务死亡的原因是什么?

时间:2015-12-18 16:15:58

标签: c# wcf iis printing

我有一个长期运行的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);
    }
}

2 个答案:

答案 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);