我需要专家意见来解决有线问题。我尝试了很多替代方案,但都失败了。
上下文:我想编写一个实用程序作为 ASP.NET Core MVC Web 应用程序,它将使用各种工作表将一些数据从数据库导出到 Excel 工作簿。
问题陈述:应用程序正在导出Excel工作簿。但是一旦用户单击下载的文件即可打开。错误消息显示文件已损坏。尽管该文件包含一些数据。
客户端代码:
$(document).on('click', '#btnDataExport', function () {
var zId = $("#deZone").val();
var fId = $("#deFactory").val();
var mId = $('#deMarket').val();
var selectedCheckboxes = $('input.chk:checked');
var selectedIds = [];
selectedCheckboxes.each(function () {
selectedIds.push($(this).attr('id'));
});
var zoneIdsStr = zId.join(',');
var marketIdsStr = mId.join(',');
var factoryIdsStr = fId.join(',');
$.ajax({
cache: false,
type: 'POST',
url: '/DataExport/DataExport',
data: {
entities: selectedIds,
zoneIds: zoneIdsStr,
marketIds: marketIdsStr,
factoryIds: factoryIdsStr
},
success: function (data) {
var blob = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'Export.xlsx';
link.click();
},
error: function () {
alert("Error while loading the page");
}
});
});
服务器端代码:
[HttpPost]
public async Task<IActionResult> DataExport(List<string> entities, List<int> zoneIds, List<int>marketIds,List<int> factoryIds)
{
// byte[] fileContents;
using (var package = new ExcelPackage())
{
foreach (var entity in entities)
{
if (string.Compare(entity, "YearlyZoneKPIs", false) == 0)
{
var yearlyZoneKPIs = _dataexportservice.GetYearlyZoneKpis(zoneIds, marketIds);
ExcelWorksheet worksheetyearlyZoneKPIs = package.Workbook.Worksheets.Add("YearlyZoneKPIs");
DataExportExcelFactory.CreateExcelForYearlyZoneKPIs(ref worksheetyearlyZoneKPIs, yearlyZoneKPIs);
}
}
}
using (MemoryStream mstream = new MemoryStream())
{
package.SaveAs(mstream);
return File(mstream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "ExportedData.xlsx");
}
}
这里
DataExportExcelFactory.CreateExcelForYearlyZoneKPIs
是一个静态方法,用于通过引用使用第二个参数中传递的数据(此处为yearlyZoneKPIs)填充Excel。
在您的代码中,放置在
using
周围的 MemoryStream
块将在 File()
结果中使用流之前处理该流,因为它是在 using
块的范围之外返回的。确保内存流保持打开且可用,直到文件完全写入响应。
这里的代码将在文件写入响应后处理 MemoryStream 的处置,因此您不需要手动处置它。
[HttpPost]
public async Task<IActionResult> DataExport(List<string> entities, List<int> zoneIds, List<int> marketIds, List<int> factoryIds)
{
using (var package = new ExcelPackage())
{
// ... (adding worksheets code)
var memoryStream = new MemoryStream();
package.SaveAs(memoryStream);
memoryStream.Position = 0;
return File(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "ExportedData.xlsx", true);
}
}
除此之外,如果您使用
$.ajax
获取数据,jQuery 可能无法正确处理二进制数据,因为它事先不知道响应的数据类型。您可以使用 Fetch API 尝试以下方法,其中 responseType
为 blob
,或者如果坚持使用 jQuery,则设置正确的
xhrFields
fetch('/DataExport/DataExport', {
method: 'POST',
body: JSON.stringify({
entities: selectedIds,
zoneIds: zoneIdsStr,
marketIds: marketIdsStr,
factoryIds: factoryIdsStr
}),
headers: {
'Content-Type': 'application/json'
}
}).then(response => response.blob())
.then(blob => {
var url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'Export.xlsx';
document.body.appendChild(a);
a.click();
a.remove();
}).catch(error => console.error('Error:', error));