使用 Rotativa 从 html 生成 PDF 时出现问题

Problem Generating a PDF from html using Rotativa

我有一个 MVC 页面,它使用 Razor 和 C# 代码的组合来呈现 html 输出。该页面在浏览器中呈现良好。但是,在我的浏览器中,当我使用 Rotativa 生成 PDF 来打印页面时,我得到的似乎是 JSON 输出而不是格式化的 PDF。

我正在使用 Visual Studio 2019 与 .NET 5.0 和 Rotativa 1.7.3。

我知道我可以尝试其他 HTML-to-PDF,但 Rotativa 似乎是最好的开源替代品。

谁能告诉我哪里做错了,这样我就可以将输出呈现为 PDF 格式?

我包含了呈现页面的代码摘录、Rotativa 代码和“PDF”输出。

 public async Task<IActionResult> PayrollView(int SelectedCompanyID, string endingWeekString, string endingDateString, int? SelectedEmployeeID)
        {
            linq query...

            PayrollReportView payrollReportView = new PayrollReportView
            {
                PayrollDetails = await payrollReport.ToListAsync()
            };

            return View(payrollReportView);
        }

public ViewAsPdf PrintPayroll(int SelectedCompanyID, string endingWeekString, string endingDateString, int? SelectedEmployeeID)
        {

            linq query...

            PayrollReportView payrollReportView = new PayrollReportView
            {
                PayrollDetails = payrollReport.ToList()
            };

            var report = new ViewAsPdf("PayrollView",payrollReportView);
            return report;
        }

浏览器中的link(我尝试了 Brave 和 Edge 并确认 Edge 打开 PDF)是:

https://localhost:44383/PayrollReports/PrintPayroll?SelectedCompanyID=13&endingWeekString=2021-11-26

JSON 样的摘录如下:... 代表附加数据,为简洁起见我排除了这些数据。

{
  "viewName": "PayrollView",
  "masterName": "",
  "model": {
    "payrollDetails": [
      {
        "earningsID": 290,
        "companyID": 13,
        "companyName": "\"D..,\"employees\":null},..\"endingDate\":null},",
        "pageSize": null,
        "pageWidth": null,
        "pageHeight": null,
        "pageOrientation": null,
        "pageMargins": {},
        "wkhtmltopdfPath": "",
        "isLowQuality": false,
        "copies": null,
        "isGrayScale": false,
        "fileName": null,
        "wkhtmlPath": "",
        "cookieName": ".ASPXAUTH",
        "formsAuthenticationCookieName": ".ASPXAUTH",
        "customHeaders": null,
        "cookies": null,
        "post": null,
        "isJavaScriptDisabled": false,
        "minimumFontSize": null,
        "proxy": null,
        "userName": null,
        "password": null,
        "customSwitches": null,
        "saveOnServerPath": null,
        "contentDisposition": 0
      }
      ...
    ]
  }
}

更新:

Edge 和 Brave 都是我的问题。我的视图和 Pdf 控制器事件如下所示。我没有 Javascript 或 AJAX 因为现在我正在做服务器端的所有事情。

public async Task<IActionResult> PayrollView(int SelectedCompanyID, string endingWeekString, string endingDateString, int? SelectedEmployeeID)
        {
            DateTime dateEndingWeek;

            // Convert endingWeek to a date variable
            if (endingWeekString == null || endingWeekString.Length == 0)
            {
                dateEndingWeek = System.DateTime.Today;
            }
            else
            {
                dateEndingWeek = DateTime.Parse(endingWeekString);
            };

            DateTime dateEndingDate;
            // Convert endingDateString to a date variable
            if (endingDateString == null || endingDateString.Length == 0)
            {
                dateEndingDate = System.DateTime.Today;
            }
            else
            {
                dateEndingDate = DateTime.Parse(endingDateString);
            };

            // Base query
            var payrollReport = from company in _context.Company
                                join employee in _context.Employees
                                on company.CompanyID equals employee.CompanyID
                                join payroll in _context.EmployeeEarnings
                                on employee.EmployeeID equals payroll.EmployeeID
                                orderby company.CompanyID, payroll.EmployeeID, payroll.WeekEndingDate
                                select new PayrollReport
                                {
                                    EarningsID = payroll.EarningsID,
                                    CompanyID = company.CompanyID,
                                    CompanyName = company.CompanyName,
                                    EmployeeID = employee.EmployeeID,
                                    EmployeeName = employee.EmployeeName,
                                    EmployeeTypeID = employee.EmployeeTypeID,
                                    SSN = employee.SSN.Substring(5, 4),
                                    WeekEndingDate = payroll.WeekEndingDate,
                                    GrossEarnings = payroll.GrossEarnings,
                                    Period401K = payroll.Period401K,
                                    Period401KCatchUp = payroll.Period401KCatchUp,
                                    FederalWithholding = payroll.FederalWithholding,
                                    SSNWithholding = payroll.SSNWithholding,
                                    MedicareWithholding = payroll.MedicareWithholding,
                                    StateWithholding = payroll.StateWithholding,
                                    NetPay = payroll.NetPay,
                                    Tips = payroll.Tips == null ? 0 : payroll.Tips,
                                    Tips_Cash = payroll.Tips_Cash == null ? 0 : payroll.Tips_Cash,
                                    FedExtraWithholding = payroll.FedExtraWithholding,
                                    StateExtraWithholding = payroll.StateExtraWithholding
                                };

            // Check Filters
            if (SelectedCompanyID != 0)
                payrollReport = payrollReport.Where(x => x.CompanyID == SelectedCompanyID);
            if (endingWeekString != null && endingDateString != null)
                payrollReport = payrollReport.Where(x => x.WeekEndingDate >= dateEndingWeek && x.WeekEndingDate <= dateEndingDate);
            else if (endingWeekString != null)
                payrollReport = payrollReport.Where(x => x.WeekEndingDate == dateEndingWeek);
            if (SelectedEmployeeID.HasValue)
                payrollReport = payrollReport.Where(x => x.EmployeeID == SelectedEmployeeID);

            PayrollReportView payrollReportView = new PayrollReportView
            {
                PayrollDetails = await payrollReport.ToListAsync()
            };

            if (endingDateString != null)
                payrollReportView.endingDate = endingDateString;

            // Calculate Sum record if an employee and "end" date are specified

            decimal grossTotal = 0;
            decimal gross401KTotal = 0;
            decimal gross401KCatchUpTotal = 0;
            decimal federalTotal = 0;
            decimal SSNTotal = 0;
            decimal medicareTotal = 0;
            decimal stateTotal = 0;
            decimal netTotal = 0;
            decimal tipsTotal = 0;
            decimal tipsCashTotal = 0;
            decimal extraFederalTotal = 0;
            decimal extraStateTotal = 0;
            foreach (var payroll in payrollReportView.PayrollDetails)
            {
                grossTotal += payroll.GrossEarnings;
                gross401KTotal += payroll.Period401K;
                gross401KCatchUpTotal += payroll.Period401KCatchUp;
                federalTotal += payroll.FederalWithholding;
                SSNTotal += payroll.SSNWithholding;
                medicareTotal += payroll.MedicareWithholding;
                stateTotal += payroll.StateWithholding;
                netTotal += payroll.NetPay;
                tipsTotal = (decimal)(tipsTotal + payroll.Tips);
                tipsCashTotal = (decimal)(tipsCashTotal + payroll.Tips_Cash);
                extraFederalTotal = (decimal)(extraFederalTotal + payroll.FedExtraWithholding);
                extraStateTotal = (decimal)(extraStateTotal + payroll.StateExtraWithholding);
            }
            payrollReportView.SumGrossEarnings = grossTotal;
            payrollReportView.SumPeriod401K = gross401KTotal;
            payrollReportView.SumPeriod401KCatchUp = gross401KCatchUpTotal;
            payrollReportView.SumFederalWithholding = federalTotal;
            payrollReportView.SumSSNWithholding = SSNTotal;
            payrollReportView.SumMedicareWithholding = medicareTotal;
            payrollReportView.SumStateWithholding = stateTotal;
            payrollReportView.SumNetPay = netTotal;
            payrollReportView.SumTips = tipsTotal;
            payrollReportView.SumTips_Cash = tipsCashTotal;
            payrollReportView.SumFederalWithholding = extraFederalTotal;
            payrollReportView.SumStateExtraWithholding = extraStateTotal;
            return View(payrollReportView);
        }

        public ViewAsPdf PrintPayroll(int SelectedCompanyID, string endingWeekString, string endingDateString, int? SelectedEmployeeID)
        {
            DateTime dateEndingWeek;

            // Convert endingWeek to a date variable
            if (endingWeekString == null || endingWeekString.Length == 0)
            {
                dateEndingWeek = System.DateTime.Today;
            }
            else
            {
                dateEndingWeek = DateTime.Parse(endingWeekString);
            };

            DateTime dateEndingDate;
            // Convert endingDateString to a date variable
            if (endingDateString == null || endingDateString.Length == 0)
            {
                dateEndingDate = System.DateTime.Today;
            }
            else
            {
                dateEndingDate = DateTime.Parse(endingDateString);
            };

            // Base query
            var payrollReport = from company in _context.Company
                                join employee in _context.Employees
                                on company.CompanyID equals employee.CompanyID
                                join payroll in _context.EmployeeEarnings
                                on employee.EmployeeID equals payroll.EmployeeID
                                orderby company.CompanyID, payroll.EmployeeID, payroll.WeekEndingDate
                                select new PayrollReport
                                {
                                    EarningsID = payroll.EarningsID,
                                    CompanyID = company.CompanyID,
                                    CompanyName = company.CompanyName,
                                    EmployeeID = employee.EmployeeID,
                                    EmployeeName = employee.EmployeeName,
                                    EmployeeTypeID = employee.EmployeeTypeID,
                                    SSN = employee.SSN.Substring(5, 4),
                                    WeekEndingDate = payroll.WeekEndingDate,
                                    GrossEarnings = payroll.GrossEarnings,
                                    Period401K = payroll.Period401K,
                                    Period401KCatchUp = payroll.Period401KCatchUp,
                                    FederalWithholding = payroll.FederalWithholding,
                                    SSNWithholding = payroll.SSNWithholding,
                                    MedicareWithholding = payroll.MedicareWithholding,
                                    StateWithholding = payroll.StateWithholding,
                                    NetPay = payroll.NetPay,
                                    Tips = payroll.Tips == null ? 0 : payroll.Tips,
                                    Tips_Cash = payroll.Tips_Cash == null ? 0 : payroll.Tips_Cash,
                                    FedExtraWithholding = payroll.FedExtraWithholding,
                                    StateExtraWithholding = payroll.StateExtraWithholding
                                };

            // Check Filters
            if (SelectedCompanyID != 0)
                payrollReport = payrollReport.Where(x => x.CompanyID == SelectedCompanyID);
            if (endingWeekString != null && endingDateString != null)
                payrollReport = payrollReport.Where(x => x.WeekEndingDate >= dateEndingWeek && x.WeekEndingDate <= dateEndingDate);
            else if (endingWeekString != null)
                payrollReport = payrollReport.Where(x => x.WeekEndingDate == dateEndingWeek);
            if (SelectedEmployeeID.HasValue)
                payrollReport = payrollReport.Where(x => x.EmployeeID == SelectedEmployeeID);

            PayrollReportView payrollReportView = new PayrollReportView
            {
                PayrollDetails = payrollReport.ToList()
            };

            if (endingDateString != null)
                payrollReportView.endingDate = endingDateString;

            // Calculate Sum record if an employee and "end" date are specified

            decimal grossTotal = 0;
            decimal gross401KTotal = 0;
            decimal gross401KCatchUpTotal = 0;
            decimal federalTotal = 0;
            decimal SSNTotal = 0;
            decimal medicareTotal = 0;
            decimal stateTotal = 0;
            decimal netTotal = 0;
            decimal tipsTotal = 0;
            decimal tipsCashTotal = 0;
            decimal extraFederalTotal = 0;
            decimal extraStateTotal = 0;
            foreach (var payroll in payrollReportView.PayrollDetails)
            {
                grossTotal += payroll.GrossEarnings;
                gross401KTotal += payroll.Period401K;
                gross401KCatchUpTotal += payroll.Period401KCatchUp;
                federalTotal += payroll.FederalWithholding;
                SSNTotal += payroll.SSNWithholding;
                medicareTotal += payroll.MedicareWithholding;
                stateTotal += payroll.StateWithholding;
                netTotal += payroll.NetPay;
                tipsTotal = (decimal)(tipsTotal + payroll.Tips);
                tipsCashTotal = (decimal)(tipsCashTotal + payroll.Tips_Cash);
                extraFederalTotal = (decimal)(extraFederalTotal + payroll.FedExtraWithholding);
                extraStateTotal = (decimal)(extraStateTotal + payroll.StateExtraWithholding);
            }
            payrollReportView.SumGrossEarnings = grossTotal;
            payrollReportView.SumPeriod401K = gross401KTotal;
            payrollReportView.SumPeriod401KCatchUp = gross401KCatchUpTotal;
            payrollReportView.SumFederalWithholding = federalTotal;
            payrollReportView.SumSSNWithholding = SSNTotal;
            payrollReportView.SumMedicareWithholding = medicareTotal;
            payrollReportView.SumStateWithholding = stateTotal;
            payrollReportView.SumNetPay = netTotal;
            payrollReportView.SumTips = tipsTotal;
            payrollReportView.SumTips_Cash = tipsCashTotal;
            payrollReportView.SumFederalWithholding = extraFederalTotal;
            payrollReportView.SumStateExtraWithholding = extraStateTotal;
            var report = new ViewAsPdf("PayrollView",payrollReportView);
            return report;
            //return new RazorPageAsPdf(this);
        }

Razor 查看代码:

@model MvcPayroll.Models.PayrollReportView

@{
    ViewData["Title"] = "Payroll Register";
}

<link rel="stylesheet" type="text/css" href="site.css" media="screen" />
<link rel="stylesheet" type="text/css" href="print.css" media="print" />

<h1>Payroll Reports</h1>
    <p><button>@Html.ActionLink("Download as PDF","PrintPayroll", "PayrollReports",
                new
                {
                    SelectedCompanyID = @ViewBag.CompanyID,
                    endingWeekString = @ViewBag.endingWeekString,
                    endingDateString = @ViewBag.endingDateString,
                    SelectedEmployeeID = @ViewBag.SelectedEmployeeId
                })</button></p>

    <table class="table">
        <thead>
            <tr>
                <th>
                    Company Name
                </th>
                <th>
                    Employee Name
                </th>
                <th>
                    SSN
                </th>
                <th>
                    Weekending Date
                </th>
                <th>
                    Gross Earnings
                </th>
                <th>
                    401K
                </th>
                <th>
                    401K Catchup
                </th>
                <th>
                    Federal Withholding
                </th>
                <th>
                    Fed Extra Withholding
                </th>
                <th>
                    SSN Withholding
                </th>
                <th>
                    Medicare Withholding
                </th>
                <th>
                    State Withholding
                </th>
                <th>
                    State Extra Withholding
                </th>
                <th>
                    Net Pay
                </th>
                <th>
                    Tips
                </th>
                <th>
                    Tips - Cash
                </th>
            </tr>
        </thead>
        <tbody>
            @{ decimal subtotalGrossEarnings = 0;
                decimal subtotalPeriod401K = 0;
                decimal subtotalPeriod401KCatchUp = 0;
                decimal subtotalFederalWithholding = 0;
                decimal subtotalSSNWithholding = 0;
                decimal subtotalMedicareWithholding = 0;
                decimal subtotalStateWithholding = 0;
                decimal subtotalNetPay = 0;
                decimal? subtotalTips = 0;
                decimal? subtotalTips_Cash = 0;
                decimal? subtotalFedExtraWithholding = 0;
                decimal? subtotalStateExtraWithholding = 0;
                string oldEmployeeName;
                if (Model != null && Model.PayrollDetails.Count() > 0)
                    oldEmployeeName = Model.PayrollDetails[0].EmployeeName;
                else
                    oldEmployeeName = string.Empty;

                @foreach (PayrollReport item in Model.PayrollDetails)
                {
                    // See if employee changed. If it did spit out the Subtotal
                    @if ((oldEmployeeName != item.EmployeeName) && (Model.endingDate != null))
                    {
                        <tr>
                            <td>
                            </td>
                            <td>
                                Sub Total:
                            </td>
                            <td>
                            </td>
                            <td>
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalGrossEarnings)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalPeriod401K)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalPeriod401KCatchUp)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalFederalWithholding)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalFedExtraWithholding)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalSSNWithholding)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalMedicareWithholding)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalStateWithholding)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalStateExtraWithholding)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalNetPay)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalTips)
                            </td>
                            <td>
                                @String.Format("{0:0.00}", subtotalTips_Cash)
                            </td>
                        </tr>
                        oldEmployeeName = item.EmployeeName;
                        subtotalGrossEarnings = item.GrossEarnings;
                        subtotalPeriod401K = item.Period401K;
                        subtotalPeriod401KCatchUp = item.Period401KCatchUp;
                        subtotalFederalWithholding = item.FederalWithholding;
                        subtotalSSNWithholding = item.SSNWithholding;
                        subtotalMedicareWithholding = item.MedicareWithholding;
                        subtotalStateWithholding = item.StateWithholding;
                        subtotalNetPay = item.NetPay;
                        subtotalTips = item.Tips;
                        subtotalTips_Cash = item.Tips_Cash;
                        subtotalFedExtraWithholding = item.FedExtraWithholding;
                        subtotalStateExtraWithholding = item.StateExtraWithholding;
                    }
                    else
                    {
                        subtotalGrossEarnings = subtotalGrossEarnings + item.GrossEarnings;
                        subtotalPeriod401K = subtotalPeriod401K + item.Period401K;
                        subtotalPeriod401KCatchUp = subtotalPeriod401KCatchUp + item.Period401KCatchUp;
                        subtotalFederalWithholding = subtotalFederalWithholding + item.FederalWithholding;
                        subtotalSSNWithholding = subtotalSSNWithholding + item.SSNWithholding;
                        subtotalMedicareWithholding = subtotalMedicareWithholding + item.MedicareWithholding;
                        subtotalStateWithholding = subtotalStateWithholding + item.StateWithholding;
                        subtotalNetPay = subtotalNetPay + item.NetPay;
                        subtotalTips = subtotalTips + item.Tips;
                        subtotalTips_Cash = subtotalTips_Cash + item.Tips_Cash;
                        oldEmployeeName = item.EmployeeName;
                        subtotalFedExtraWithholding = subtotalFedExtraWithholding + item.FedExtraWithholding;
                        subtotalStateExtraWithholding = subtotalStateExtraWithholding + item.StateExtraWithholding;
                    }

                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => item.CompanyName)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.EmployeeName)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.SSN)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.WeekEndingDate)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.GrossEarnings)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Period401K)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Period401KCatchUp)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.FederalWithholding)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.FedExtraWithholding)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.SSNWithholding)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.MedicareWithholding)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.StateWithholding)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.StateExtraWithholding)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.NetPay)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Tips)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Tips_Cash)
                        </td>
                    </tr>
                }
            }
            @if (Model.endingDate != null)
            {
                <tr>
                    <td>
                    </td>
                    <td>
                        Sub Total:
                    </td>
                    <td>
                    </td>
                    <td>
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalGrossEarnings)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalPeriod401K)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalPeriod401KCatchUp)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalFederalWithholding)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalFedExtraWithholding)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalSSNWithholding)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalMedicareWithholding)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalStateWithholding)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalStateExtraWithholding)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", @subtotalNetPay)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalTips)
                    </td>
                    <td>
                        @String.Format("{0:0.00}", subtotalTips_Cash)
                    </td>
                </tr>
            }
        </tbody>
        <tfoot>
            @if (Model.endingDate != null)
            {
                <tr>
                    <td>
                        Totals
                    </td>
                    <td>
                    </td>
                    <td>
                    </td>
                    <td>
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumGrossEarnings)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumPeriod401K)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumPeriod401KCatchUp)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumFederalWithholding)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumFedExtraWithholding)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumSSNWithholding)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumMedicareWithholding)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumStateWithholding)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumStateExtraWithholding)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumNetPay)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumTips)
                    </td>
                    <td>
                        @Html.DisplayFor(model => Model.SumTips_Cash)
                    </td>
                </tr>
            }
        </tfoot>
    </table>

旭东,你说的响应头错误是对的。我下载了一个有效的 .net 项目。然后我又做了一些在线搜索,发现我使用的是 .net Core,所以我需要下载 Rotativa 的 .net Core 版本,而不是 .net 4.6 版本。在 link、PDFCore 的一些帮助下,我能够让我的程序生成 PDF。