【问题标题】:Reasons for long-running WCF service dying?长期运行的 WCF 服务死亡的原因是什么?
【发布时间】: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);
    }
}

【问题讨论】:

    标签: c# wcf iis printing


    【解决方案1】:

    我建议检查您的打印方法的操作合同。当 isOneWay 属性未设置或在 void 方法上设置为 false 时,我看到 WCF 服务失败。试试这样的

        [OperationContract(IsOneWay=true)]
        public void PrintDocumentWithSettings(PageSettings settings, PrinterSettings settings);
    

    【讨论】:

    • 感谢您的建议。但是,它不是一个无效的方法。我将使用 WCF 服务接口更新描述
    【解决方案2】:

    它在 Windows 事件日志中:

    进程 ID 为“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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-11
      相关资源
      最近更新 更多