您不能通过 AJAX 调用直接返回文件以供下载,因此,另一种方法是使用 AJAX 调用将相关数据发布到您的服务器。然后,您可以使用服务器端代码创建 Excel 文件(我建议为此使用 EPPlus 或 NPOI,尽管这听起来好像您有这部分工作)。
2016 年 9 月更新
我的原始答案(如下)已经超过 3 年了,所以我想我会更新,因为通过 AJAX 下载文件时我不再在服务器上创建文件但是,我留下了原始答案,因为它可能仍然有一些用途,具体取决于您的具体要求。
我的 MVC 应用程序中的一个常见场景是通过具有一些用户配置的报告参数(日期范围、过滤器等)的网页进行报告。当用户指定了他们发布到服务器的参数时,会生成报告(例如作为输出的 Excel 文件),然后我将生成的文件作为字节数组TempData
存储在具有唯一引用的存储桶中。此引用作为 Json 结果传回给我的 AJAX 函数,该函数随后重定向到单独的控制器操作,以从TempData
最终用户浏览器中提取数据并下载数据。
为了更详细地说明这一点,假设您有一个 MVC 视图,它的表单绑定到了 Model 类,让我们调用 Model ReportVM
。
首先,需要一个控制器操作来接收发布的模型,例如:
public ActionResult PostReportPartial(ReportVM model){
// Validate the Model is correct and contains valid data
// Generate your report output based on the model parameters
// This can be an Excel, PDF, Word file - whatever you need.
// As an example lets assume we've generated an EPPlus ExcelPackage
ExcelPackage workbook = new ExcelPackage();
// Do something to populate your workbook
// Generate a new unique identifier against which the file can be stored
string handle = Guid.NewGuid().ToString();
using(MemoryStream memoryStream = new MemoryStream()){
workbook.SaveAs(memoryStream);
memoryStream.Position = 0;
TempData[handle] = memoryStream.ToArray();
}
// Note we are returning a filename as well as the handle
return new JsonResult() {
Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
};
}
将我的 MVC 表单发布到上述控制器并接收响应的 AJAX 调用如下所示:
$ajax({
cache: false,
url: '/Report/PostReportPartial',
data: _form.serialize(),
success: function (data){
var response = JSON.parse(data);
window.location = '/Report/Download?fileGuid=' + response.FileGuid
+ '&filename=' + response.FileName;
}
})
处理文件下载的控制器操作:
[HttpGet]
public virtual ActionResult Download(string fileGuid, string fileName)
{
if(TempData[fileGuid] != null){
byte[] data = TempData[fileGuid] as byte[];
return File(data, "application/vnd.ms-excel", fileName);
}
else{
// Problem - Log the error, generate a blank file,
// redirect to another controller action - whatever fits with your application
return new EmptyResult();
}
}
如果需要,可以轻松适应的另一项更改是将文件的 MIME 类型作为第三个参数传递,以便一个控制器操作可以正确地为各种输出文件格式提供服务。
这消除了在服务器上创建和存储任何物理文件的任何需要,因此不需要日常管理,这对最终用户来说也是无缝的。
请注意,使用TempData
而不是的优点Session
是一旦TempData
读取数据就会被清除,因此如果您有大量文件请求,它将在内存使用方面更有效。请参阅TempData 最佳实践。
原始答案
您不能通过 AJAX 调用直接返回文件以供下载,因此,另一种方法是使用 AJAX 调用将相关数据发布到您的服务器。然后,您可以使用服务器端代码创建 Excel 文件(我建议为此使用 EPPlus 或 NPOI,尽管这听起来好像您有这部分工作)。
在服务器上创建文件后,将文件的路径(或只是文件名)作为 AJAX 调用的返回值传回,然后将 JavaScriptwindow.location
设置为此 URL,这将提示浏览器下载文件。
从最终用户的角度来看,文件下载操作是无缝的,因为他们永远不会离开发出请求的页面。
下面是一个简单的 ajax 调用示例来实现这一点:
$.ajax({
type: 'POST',
url: '/Reports/ExportMyData',
data: '{ "dataprop1": "test", "dataprop2" : "test2" }',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (returnValue) {
window.location = '/Reports/Download?file=' + returnValue;
}
});
- url参数是您的代码将在其中创建 Excel 文件的控制器/操作方法。
- data参数包含将从表单中提取的 json 数据。
- returnValue将是您新创建的 Excel 文件的文件名。
- window.location命令重定向到实际返回文件以供下载的 Controller/Action 方法。
下载操作的示例控制器方法是:
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}