【发布时间】:2021-12-07 23:08:32
【问题描述】:
我有一个 MVC 页面,它使用 Razor 和 C# 代码的组合来呈现 html 输出。该页面在浏览器中呈现良好。但是,在我的浏览器中,当我使用 Rotativa 生成 PDF 来打印页面时,我得到的似乎是 JSON 输出,而不是格式化的 PDF。
我正在使用带有 .NET 5.0 和 Rotativa 1.7.3 的 Visual Studio 2019。
我知道我可以尝试其他 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;
}
浏览器中的链接(我尝试了 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>
【问题讨论】:
-
我对你的问题有点困惑。它不能在 Bravo 中正确呈现为 PDF 文件吗?还是边缘?我找到了similar case,这可能对你有帮助。
-
它在 Bravo 和 Edge 中都不能正确渲染。我尝试了您发送给我的链接,但我遇到了一些问题。被扩展的类是 PageModel,但我的类是控制器。此外,CallTheDriver 有一个覆盖,但它不允许我覆盖这个类。我是否使用了错误版本的 Rotativa?此外,该链接说 Rotativa 不适用于 Razor,但在其他一些帖子中,我发现 Razor 似乎可以正常工作。
-
嗨,@大卫。我使用 Rotativa 始终基于 Razor 视图生成 PDF,并且它工作正常,如您之前所述。结果接收到纯 JSON 可能与您的客户端代码中的一些问题有关,请您分享您的 Razor 视图代码和您用于调用控制器操作的 javaascript/AJAX 吗?为了澄清起见,我假设您正试图让您的应用程序在 Brave 和 Edge 上都运行,这在 Edge 上运行良好,在 Brave 中失败?
-
我创建了一个简单的示例并在 Edge 版本 96.0.1054.53(官方版本)中对其进行了测试,正如 Dave Miler 所说,它运行良好。类似于this。你能检查一下响应头中的
content-type属性,它应该是application/pdf。 -
旭东感谢您的帮助。您的帖子让我深入挖掘并找出解决问题的方法。
标签: c# microsoft-edge .net-5 rotativa