您不能通过AJAX调用直接返回要下载的文件,因此,另一种方法是使用AJAX调用将相关数据发布到服务器.然后,您可以使用服务器端代码来创建Excel文件(我建议使用EPPlus或NPOI来实现这一点,尽管听起来好像您的这个部分正在工作).
UPDATE September 2016
我的原始答案(如下)已经有3年多的历史了,所以我想我会更新,因为我在通过AJAX下载文件时不再在服务器上创建文件.然而,我保留了原始答案,因为它可能仍然有一些用途,这取决于您的具体要求.
在我的MVC应用程序中,一个常见的场景是通过具有一些用户配置的报告参数(日期范围、过滤器等)的网页进行报告.当用户指定了将其发布到服务器的参数后,将生成报告(例如,一个Excel文件作为输出),然后我将生成的文件作为字节数组存储在具有唯一引用的TempData
bucket中.此引用作为Json结果传递回我的AJAX函数,该函数随后重定向到单独的控制器操作,以从TempData
中提取数据并下载到最终用户浏览器.
To give this more detail, assuming you have a MVC View that has a form bound to a Model class, lets call the Model ReportVM
.
First, a controller action is required to receive the posted model, an example would be:
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;
}
})
The controller action to handle the downloading of the file:
[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();
}
}
One other change that could easily be accommodated if required is to pass the MIME Type of the file as a third parameter so that the one Controller action could correctly serve a variety of output file formats.
This removes any need for any physical files to created and stored on the server, so no housekeeping routines required and once again this is seamless to the end user.
Note, the advantage of using TempData
rather than Session
is that once TempData
is read the data is cleared so it will be more efficient in terms of memory usage if you have a high volume of file requests. See TempData Best Practice.
ORIGINAL Answer个
您不能通过AJAX调用直接返回要下载的文件,因此,另一种方法是使用AJAX调用将相关数据发布到服务器.然后,您可以使用服务器端代码来创建Excel文件(我建议使用EPPlus或NPOI来实现这一点,尽管听起来好像您的这个部分正在工作).
Once the file has been created on the server pass back the path to the file (or just the filename) as the return value to your AJAX call and then set the JavaScript window.location
to this URL which will prompt the browser to download the file.
From the end users perspective, the file download operation is seamless as they never leave the page on which the request originates.
下面是一个简单的人为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;
}
});
- 参数是您的代码将在其中创建Excel文件的控制器/操作方法.
- data参数包含将从表单中提取的json数据.
- returnValue将是新创建的Excel文件的文件名.
- window.location命令重定向到实际返回文件供下载的控制器/操作方法.
下载操作的示例控制器方法为:
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}