首页 > 解决方案 > 使用 wkhtmlToPdf 在大多数情况下都会失败(卡在加载中),但会成功 10 次

问题描述

我正在使用 wkhtmlToPdf(实际上是 rotativa)将视图打印为 pdf。我已经成功地将视图打印为 pdf 多次。但是一旦成功,它就会失败 10-50 次,然后才能再次工作。无论视图中有多少数据或其他任何数据。为了使它第一次工作,我还必须在实际加载 5 个中的一个之前加载 5 次 pdf。其余的只是继续加载(一次加载大约 6 个小时,什么也没做)。这是我调用 ViewAsPdf 方法的代码

public IActionResult PrintPdf()
{
    GraphsViewModel graphsView = new GraphsViewModel();
        graphsView = HttpContext.Session.GetObjectSingle<GraphsViewModel>("graphsViewModel");
        graphsView.PdfFormat = true;



    return new Rotativa.AspNetCore.ViewAsPdf("GraphsPdf", graphsView) { CustomSwitches = "--no-stop-slow-scripts --window-status ready" };
}

在 View 中调用方法是这样的:

<div class="btn btn-default">
    <a href="@Url.Action("PrintPdf", "Home")" target="_blank"><img src="~/images/pdf.png" width="40" /></a>
</div>    

视图中有一些繁重的数据,但就像我说的,如果它只工作一次,为什么不能每次都工作。提前致谢!

编辑:我的视图的代码很多,但其中最大的部分是正在加载的谷歌图表。很多可能没有什么意义,因为您对我显示的数据没有任何背景,但这对我遇到的问题并不重要。

@model project.Models.ViewModels.GraphsViewModel
@using project
@using project.Models
@using project.Models.Domain
@using project.Models.ViewModels


@{
    string[] xas = Model.EfficiencyString;
    double[] yas = Model.EfficiencyDouble;
    List<string> impacts = Model.impacts;
    List<string> urgenties = Model.urgenties;
    int[,] Priorities = Model.prioriteiten;
    List<string> categories = Model.Categories;
    int[] NrPerCategory = Model.NrPerCategory;
    List<string> uniqueGroups = Model.uniqueGroups;
    List<string> allNames = Model.allNames;
    MultiKeyDictionary<string, string, int> namesPerGroup = Model.namesPerGroup;

}
<head>

    @{
        ViewData["Title"] = "Graphs";
        Layout = "~/Views/Shared/_LayoutGraphs.cshtml";
    }

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">
        //debugger;
// Load the Visualization API and the corechart package.
    google.charts.load('current', { 'packages': ['corechart'] });
    // Set a callback to run when the Google Visualization API is loaded. 
    google.charts.setOnLoadCallback(drawAmountPerCategory);
    google.charts.setOnLoadCallback(drawIncNivStacked);
    google.charts.setOnLoadCallback(drawIncNiv);
    google.charts.setOnLoadCallback(drawEfficiency);

    // Callback that creates and populates a data table,instantiates the pie chart, passes in the data and draws it.
        function drawEfficiency() {

        var data = new google.visualization.DataTable();
        @{
            @:data.addColumn('string', 'Status');
            @:data.addColumn('number','Aantal');

            for (var k = 0; k < @yas.Length; k++)
            {
                @:data.addRows([['@xas[k]',@yas[k]]]);
            }
        }


        var options = {
            'title': 'Aantal tickets in functie van de status',
            'width': '1140',
            'height': '200',
        };

        var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
        google.visualization.events.addListener(chart, 'ready', myReadyHandler);
        chart.draw(data, options);
    };
    Category
    function drawAmountPerCategory()
    {

        var data = new google.visualization.DataTable();

        data.addColumn('string', 'Categorieën');
        data.addColumn('number', 'Aantal');
        data.addColumn({ type: 'number', role: 'annotation' })
        @{
            for (var c = 0; c < categories.Count(); c++)
            {
                if (!(NrPerCategory[c] == 0))
                {
                    string categorie = categories[c];

                    @:data.addRows([['@categorie',@NrPerCategory[c],@NrPerCategory[c]]]);
                }
            }

        }

        var options = {
            title: 'Aantal tickets per categorie',
            'width': '1140',
            'height': '200',
            hAxis: {
                title: 'Categorieën',
                slantedText: true
            },
            chartArea: {
                top: 28,
                height: '40%',
                width: '80%'
            },
            vAxis: {
                title: 'Aantal'
            },
            legend: {position: 'none'}
        };
        data.sort([{ column: 1, desc: true }]);
        var categorieChart = new google.visualization.ColumnChart(document.getElementById('cat_chart'));
        categorieChart.draw(data, options);

    }

    function drawIncNiv()
    {

        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Soort incident');
        data.addColumn('number', 'Aantal');
        data.addColumn({ type: 'number', role: 'annotation' })

        data.addRows([['P1',@Priorities[1, 1],@Priorities[1, 1]]]);
        data.addRows([['P2',@Priorities[1, 2] + @Priorities[2, 1],@Priorities[1, 2] + @Priorities[2, 1]]]);
        data.addRows([['P3',@Priorities[1, 3] + @Priorities[2, 2] + @Priorities[3, 1],@Priorities[1, 3] + @Priorities[2, 2] + @Priorities[3, 1]]]);
        data.addRows([['P4',@Priorities[2, 3] + @Priorities[2, 4] + @Priorities[3, 2] + @Priorities[3, 3] + @Priorities[1, 4],@Priorities[2, 3] + @Priorities[2, 4] + @Priorities[3, 2] + @Priorities[3, 3] + @Priorities[1, 4]]]);
        data.addRows([['P5',@Priorities[3, 4],@Priorities[3, 4]]]);


        var options = {
            title: 'Aantal tickets per Incident niveau',
            'width': '1140',
            'height': '200',
            hAxis: {
                title: 'Incident niveau',

            },
            vAxis: {
                title: 'Aantal tickets'
            },
            chartArea: {
                top: 28,
                height: '40%',
                width: '80%'
            },
            legend: { position: 'none' }
        };


        var categorieChart = new google.visualization.ColumnChart(document.getElementById('incniv_chart'));
        categorieChart.draw(data, options);
    }

    function drawIncNivStacked()
    {

        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Impact');
        data.addColumn('number', 'Unable to Work');
        data.addColumn('number', 'Critical Business Process Unavailable');
        data.addColumn('number', 'Normal Business Process Unavailable');
        data.addColumn('number', 'Incident, but Workaround Available');
        data.addColumn('number', 'Service Request');
        data.addColumn('number', 'Not Set');
        data.addColumn({ type: 'number', role: 'annotation' });

        @{for (var m = 1; m < impacts.Count() + 1; m++)
            {
                int som = Priorities[m, 1] + Priorities[m, 2] + Priorities[m, 3] + Priorities[m, 4] + Priorities[m, 5] + Priorities[m, 6];

                @:data.addRows([['@impacts[m - 1]', @Priorities[m, 1], @Priorities[m, 2], @Priorities[m, 3], @Priorities[m, 4], @Priorities[m, 5], @Priorities[m, 6], @som]]);

            }
        }


        var options = {
            title: 'Aantal tickets per Impact',
            'width': '1140',
            'height': '200',
            isStacked: true,
            vAxis: {
                title: 'Aantal tickets'
            },
            chartArea: {
                top: 28,
                height: '70%',
                width: '80%'
            }
        };


        var categorieChart = new google.visualization.ColumnChart(document.getElementById('incnivStacked_chart'));
        categorieChart.draw(data, options);
    }

        function CallBackForDrawingPdf() {
            drawAmountPerCategory();
            drawIncNivStacked();
            drawIncNiv();
            drawEfficiency();
        }


        function myReadyHandler() {
            window.status = "ready";
        }

    </script>

</head>
<body onload="CallBackForDrawingPdf()">
    <!-- Titel en de gekozen filter-->
    @if (Model.PdfFormat == false) {
        <h2>Graphs</h2>
        <h3>@ViewBag.filter</h3>
        <div class="btn btn-default">
            <a href="@Url.Action("PrintPdf", "Home")" target="_blank"><img src="~/images/pdf.png" width="40" /></a>
        </div>
    }


    <table class="table table-striped table-condensed table-bordered table-responsive table-hover">
        <tr>
            <th>Impact</th>
            @{
                foreach (var urg in urgenties)
                {
                    <th>@urg</th>
                }

            }
        </tr>
        @{
            int counter_imp = 1;
            foreach (var mod in impacts)
            {
                int counter_urg = 1;
                <tr>
                    <td>@mod</td>
                    @{
                        foreach (var urg in urgenties)
                        {
                            string value = @Priorities[counter_imp, counter_urg].ToString();
                            <td>@Html.ActionLink(value, "SlaFilter", new { imp = @impacts[counter_imp - 1], urg = @urgenties[counter_urg - 1] })</td>
                            counter_urg++;
                        }

                        counter_imp++;
                    }
                </tr>
            }
        }
    </table>
    <div id="chartparent">
        <!-- De div elementen bevatten elk een grafiek. De lijnen (hr) zijn puur voor wat overzicht op de pagina te creëren.-->
        <hr style="width: 100%; color: black; height: 3px; background-color:dimgrey;" />
        <div id="cat_chart"></div>
        <div id="test_chart"></div>
        <div id="incniv_chart"></div>
        <div id="incnivStacked_chart"></div>
        <div id="chart_div"></div>
        <!-- De tabel waar per groep staat hoeveel tickets een persoon heeft behandeld.-->
        <br />

        <hr style="width: 100%; color: black; height: 3px; background-color:dimgrey;" />
    </div>
    <h4>PIVOT</h4>
    <br />
    @{
        <table class="table table-condensed table-bordered table-responsive table-striped table-hover ">
            @{int nr = 0;
                int counter = 0;}
            @{
                // Overlopen van alle groepen
                foreach (var gr in uniqueGroups)
                {
                    string amount = "";
                    string id1 = ".group" + nr.ToString();
                    string id2 = "group" + nr.ToString();


                    foreach (var n in allNames)
                    {
                        if (namesPerGroup.ContainsKey(gr, n))
                        {
                            counter = counter + namesPerGroup[gr, n];
                        }
                    }
                    if (gr.Equals("NULL"))
                    {
                        <tr>
                            <th colspan="2" data-toggle="collapse" data-target="@id1" class="clickable danger">Not Set <b style="float: right;">@counter</b></th>
                        </tr>
                    }
                    else
                    {
                        <tr>
                            <th colspan="2" data-toggle="collapse" data-target="@id1" class="clickable info">@gr <b style="float: right;">@counter</b></th>
                        </tr>
                    }

                    foreach (var n in allNames)
                    {
                        if (namesPerGroup.ContainsKey(gr, n))
                        {
                            <tr>
                                <td class="collapse in @id2 "> <i>@n </i> <i style="float: right;">@amount </i></td>
                            </tr>
                        }
                    }

                    nr++;
                    counter = 0;
                }
            }
        </table>
    }
</body>

标签: c#asp.netrazormodel-view-controller

解决方案


您可以将window.status其用作 wkhtmltopdf 的更好指标。

在您的页面中,当您知道页面准备就绪时,您可以将其放入(如果您使用 jquery 或,则文档准备就绪window.addEventListener("load"

window.status = "ReadyToPrint";

然后,您可以简化 wkhtmltopdf 参数:

"--no-stop-slow-scripts --window-status ReadyToPrint"

推荐阅读