使用Ajax.BeginForm下载文件
使用Ajax.BeginForm下载文件
我在MVC中有一个相对较大的表单。\n我需要能够生成一个包含来自该表单子集的数据的Excel文件。\n棘手的是,这不应影响表单的其余部分,所以我想通过AJAX来实现。我在SO上遇到了一些相关的问题,但我无法完全理解答案的意思。\n这个问题似乎最接近我想要的:asp-net-mvc-downloading-excel - 但我不确定我理解回答的意思,并且这个问题已经几年没有更新了。我还遇到了另一篇文章(现在找不到了),关于使用iframe来处理文件下载,但我不知道如何在MVC中使其工作。\n如果我正在进行完整的提交,我的Excel文件可以正常返回,但是我无法在MVC中使用AJAX使其工作。
有时候在MVC中,我们需要使用Ajax.BeginForm来下载文件。在下面的内容中,作者分享了他的代码,并提到了问题的出现以及解决方法。
问题的出现原因是,作者之前尝试了一种方法来下载文件,但是并没有使用Ajax。他通过一个简单的JavaScript函数来实现文件下载,当点击按钮时,该函数会触发:
function getWinnersExcel(drawingId) { window.location = "/drawing/drawingwinnersexcel?drawingid=" + drawingId; }
然后,作者在C#的控制器代码中实现了下载文件的功能。他使用了一个MemoryStream来存储文件,通过Entity Framework来获取数据,并使用一个第三方工具GemBox.Spreadsheet生成Excel文件并保存到流中。最后,他将流返回给前端,使得浏览器能够下载文件:
public FileResult DrawingWinnersExcel(int drawingId) { MemoryStream stream = new MemoryStream(); ListwinnerList = DrawingDataAccess.GetWinners(drawingId); ExportHelper.GetWinnersAsExcelMemoryStream(stream, winnerList, drawingId); string suggestedFilename = string.Format("Drawing_{0}_Winners.xlsx", drawingId); return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", suggestedFilename); }
作者在ExportHelper类中使用了GemBox.Spreadsheet这个第三方工具来生成Excel文件,并将其保存到流中。在IE、Chrome和Firefox浏览器中,浏览器会提示下载文件,并且不会发生实际的导航。
作者提到他之前也尝试了类似的方法来下载文件,但是问题是无法确定下载何时完成,从而无法停止预加载动画。
所以,作者提供的解决方法是使用Ajax.BeginForm来实现文件下载功能,并且可以通过检查下载是否完成来停止预加载动画。
问题出现的原因:用户在下载文件时遇到了文件访问问题,可能需要处理文件访问权限、文件管理和删除等问题。
解决方法:将文件存储在会话缓存中,而不是在服务器上作为物理文件存储。为缓存变量(存储Excel文件)使用一个唯一生成的名称,这将是初始Ajax调用的返回值。这样可以避免处理文件访问问题、管理(删除)不需要的文件等,并且在缓存中存储文件可以更快地检索。
示例代码如下(以存储在缓存中为例,不包括生成Excel文件的代码):
// 将文件存储在缓存中
byte[] excelData = GenerateExcelFile(); // 生成Excel文件数据
string cacheKey = Guid.NewGuid().ToString(); // 生成唯一的缓存键
HttpContext.Current.Cache.Insert(cacheKey, excelData); // 将Excel文件数据存储在缓存中
return cacheKey; // 将缓存键作为Ajax调用的返回值
问题的可扩展性:如果用户正在下载多个大型报表,这种方法是否可扩展?
如果您正在使用Azure,会话将在关闭ARRAffinity之前一直有效。
问题的原因是无法直接通过AJAX调用返回文件进行下载,解决方法是使用AJAX调用将相关数据发送到服务器,然后使用服务器端代码创建Excel文件,并将文件存储为字节数组。然后将唯一标识符作为Json结果返回给AJAX函数,然后重定向到另一个控制器动作以从TempData中提取数据并下载到用户浏览器。使用TempData而不是Session的好处是一旦TempData被读取,数据就会被清除,因此如果您有大量的文件请求,它将在内存使用方面更高效。另外,还可以通过将文件的MIME类型作为第三个参数传递,使一个控制器动作能够正确提供各种输出文件格式。这样就不需要在服务器上创建和存储任何物理文件,因此不需要进行任何维护工作,对最终用户来说,文件下载操作是无缝的,因为他们从未离开发出请求的页面。