首页 > 解决方案 > iTextSharp XMLParser.Parse 反复抛出并吞下异常

问题描述

我有一个函数用于尝试为 iTextSharp 提供一些 HTML 并从中生成 PDF。这个函数成功地生成了带有 CSS 样式的 PDF,但它的运行速度不足以满足我们的要求。

我已经注意到一个特别需要很长时间才能执行的区域是调用XMLParser.Parse,我看到一个 8 页的文档需要超过 14 秒才能完成,该文档显示的只是一个以图标为标题的数据表。在执行此方法期间,我注意到(在输出窗口中)三个异常被 iTextSharp 或 iTextSharp 调用的代码抛出(并且可能被捕获)。这些例外是:

  1. mscorlib.dll 中的“System.Collections.Generic.KeyNotFoundException”
  2. itextsharp.xmlworker.dll 中的“iTextSharp.tool.xml.exceptions.NoDataException”
  3. mscorlib.dll 中的“System.ArgumentException”

在 Parse 方法完成执行之前,这三个异常会重复(尽管不一定按此顺序)。

虽然我意识到我不需要自己处理这些异常,但我之所以提到它们,是因为我正在尝试提高此方法的性能并了解捕获异常可能是一项昂贵的操作。我正在寻找的是引发这些异常的原因是什么,如果它取决于我传入的坏数据,那么坏的数据是什么?

这是目前的 HTML 到 PDF 功能。请注意,我已经XMLWorkerFontProvider.DONTLOOKFORFONTS按照 itext_so 手册的建议尝试过使用,但这样做并没有带来任何性能提升。我还注意到一次NullReferenceException被抛出和吞下PdfWriter.GetInstance;我想知道这是否也与Parse方法中抛出的异常有关。

public static byte[] GeneratePdfFromHtml(string html, Action<PdfWriter, Document> pdfSettings = null, string additionalFooterText = null)
{
    var tagProcessor = (DefaultTagProcessorFactory)Tags.GetHtmlTagProcessorFactory();

    tagProcessor.RemoveProcessor(HTML.Tag.IMG);
    tagProcessor.AddProcessor(HTML.Tag.IMG, new CustomProcessorImageTag());

    using (var workStream = new MemoryStream())
    using (var document = new Document())
    //NOTE: The NullReferenceException is thrown via this call.
    using (PdfWriter writer = PdfWriter.GetInstance(document, workStream))
    {
        PdfEventHelper pdfEventHelper = new PdfEventHelper(additionalFooterText);

        writer.PageEvent = pdfEventHelper;
        writer.CloseStream = false;
        pdfSettings?.Invoke(writer, document);
        document.Open();

        var xmlWorkerFontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);

        //Not noticably faster without this font directory registration.
        xmlWorkerFontProvider.RegisterDirectory("~/Content/fonts", false);

        //TODO: If further performance is needed then this line is the next slowest (.43ms).
        var htmlContext = new HtmlPipelineContext(new CssAppliersImpl(xmlWorkerFontProvider));

        htmlContext.SetTagFactory(tagProcessor);

        Func<string, string> mapPath = HttpContext.Current.Server.MapPath;
        var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(true);

        foreach (var cssFileName
            in new[]
            {
                "bootstrap.min.css",
                "Pdf.css",
                "Rdp.css"
            })
            cssResolver.AddCssFile(mapPath($"~/Content/{cssFileName}"), true);

        using (var reader = new StringReader(html))
        {
            new XMLParser(
                new XMLWorker(
                    new CssResolverPipeline(
                        cssResolver,
                        new HtmlPipeline(
                            htmlContext,
                            new PdfWriterPipeline(
                                document,
                                writer))),
                    true))
            //TODO: Speed up this line - this is the slowest line in the method by far.
            //NOTE: This throws a series of ArgumentExceptions, NoDataExceptions and KeyNotFoundExceptions.
            .Parse(reader);

            document.Close();

            return workStream.ToArray();
        }
    }
}

标签: c#itext

解决方案


推荐阅读