初次转换后悬挂TuesPechkin

BM-*_*BM- 5 c# pdf wkhtmltopdf asp.net-web-api iis-8.5

我正在尝试创建一个可以将样式化HTML文件转换为PDF的Web API.

我正在使用TuesPechkin并将我的应用程序安装到IIS中(作为32位应用程序:我已将应用程序池修改为以32位模式运行).

IIS 8.5正在Windows Server 2012 R2上运行.

C#中的PDFConversion类:

using System.Drawing.Printing;
using System.IO;
using TuesPechkin;

namespace PDFApi
{
    public class PDFcreator
    {
        public void convert(string path, string uri)
        {
            IConverter converter = new StandardConverter(
                new RemotingToolset<PdfToolset>(
                    new Win64EmbeddedDeployment(
                    new TempFolderDelpoyment())));

            var document = new HtmlToPdfDocument
            {
                GlobalSettings =
                {
                    ProduceOutline = true,
                    DocumentTitle = "Converted Form",
                    PaperSize = PaperKind.A4,
                    Margins =
                    {
                        All = 1.375,
                        Unit = Unit.Centimeters
                    }
                },
                Objects =
                {
                    new ObjectSettings { RawData = File.ReadAllBytes(uri) }
                }
            };

            byte[] pdfBuf = converter.Convert(document);

            FileStream fs = new FileStream(path, FileMode.Create);
            fs.Write(pdfBuf, 0, pdfBuf.Length);
            fs.Close();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

财务主任如下:

    [Route("converthtml")]
    [HttpPost]
    [MIMEContentFilter]
    public async Task<HttpResponseMessage> ConvertHtml()
    {
        string temppath = System.IO.Path.GetTempPath();

        var streamProvider = new MultipartFormDataStreamProvider(temppath);
        await Request.Content.ReadAsMultipartAsync(streamProvider);


        string filepath = streamProvider.FileData.Select(entry => entry.LocalFileName.Replace(temppath + "\\", "")).First<string>();
        string pdfpath = System.IO.Path.GetTempFileName();
        pdfpath = pdfpath.Substring(0, pdfpath.LastIndexOf('.')) + ".pdf";

        new PDFcreator().convert(pdfpath, filepath);

        var stream = new FileStream(pdfpath, FileMode.Open);
        var result = new HttpResponseMessage(HttpStatusCode.OK);
        result.Content = new StreamContent(stream);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        return result;
    }
Run Code Online (Sandbox Code Playgroud)

这里有点奇怪:在Fiddler试验,发送一次文件会立即返回PDF.但是,所有后续的POST都会让Fiddler挂起.检查任务管理器显示此任务的CPU和内存分别跳至13.5%和~96MB.

Temp文件夹(存储文件的位置)在成功运行时将包含三个文件:原始上传文件(以类似GUID的名称存储),通过wkHtmlToPdf生成的文件(格式为"wktemp-") ),以及生成的pdf(作为tempXXXX.pdf).在它挂起的情况下,只能找到第一个文件,表明问题出在wkHtmlToPdf本身的某个地方.

然而,真正的踢球者是在任务管理器中手动杀死进程,API成功完成,返回pdf,完全创建!

如果重置IIS,则进程返回到原始状态; 一个新的尝试将毫无问题地工作.

显然,每次调用后重置IIS都不太可行,也不是每次都手动终止进程...

这是一个错误/这个问题是否有任何解决方案?

Tos*_*nev 8

            var tempFolderDeployment = new TempFolderDeployment();
            var win32EmbeddedDeployment = new Win32EmbeddedDeployment(TempFolderDeployment);
            var remotingToolset = new RemotingToolset<PdfToolset>(Win32EmbeddedDeployment);

            var converter =
                 new ThreadSafeConverter(RemotingToolset);


            byte[] pdfBuf = converter.Convert(document);
            remotingToolset.Unload();
Run Code Online (Sandbox Code Playgroud)

卸载remotingToolset将阻止挂起 RemotingToolset.Unload();

  • 这是我有史以来最好的答案,这是调试和纯净运气的日子。仍然没有将其标记为已回答。好难过.... (2认同)

Zvi*_*ler 3

很重要-

@toshkata-tonev 的回答对我有帮助,但是当很多会话使用此功能时,我们的服务器因 CPU 过多而崩溃!

要点是该进程应该作为静态共享函数由所有会话共享。

所以这对我来说是解决方案:

实现:在您的应用程序中创建一个静态类:

public static class TuesPechkinInitializerService {
    private static string staticDeploymentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wkhtmltopdf");

public static void CreateWkhtmltopdfPath()
    {
        if (Directory.Exists(staticDeploymentPath) == false)
        {
            Directory.CreateDirectory(staticDeploymentPath);
        }
    }

    public static IConverter converter = 
        new ThreadSafeConverter(
            new RemotingToolset<PdfToolset>(
                new Win64EmbeddedDeployment(
                    new StaticDeployment(staticDeploymentPath)
                )
            )
        );
}
Run Code Online (Sandbox Code Playgroud)

在 GLOBAL.asax 中,我在项目启动时初始化该类:

TuesPechkinInitializerService.CreateWkhtmltopdfPath();
Run Code Online (Sandbox Code Playgroud)

并使用它:

HtmlToPdfDocument pdfDocument = new HtmlToPdfDocument
                {
                    GlobalSettings = new GlobalSettings(),
                    Objects =
                    {
                        new ObjectSettings
                        { 
                            ProduceLocalLinks = true,
                            ProduceForms = true,
                            HtmlText = htmlContent
                        }                    
                    }
                };

                byte[] pdfDocumentData = TuesPechkinInitializerService.converter.Convert(pdfDocument);
Run Code Online (Sandbox Code Playgroud)

谢谢:

https://github.com/tuespetre/TuesPechkin/issues/152