通过 AJAX MVC 下载 Excel 文件 [英] Download Excel file via AJAX MVC

查看:34
本文介绍了通过 AJAX MVC 下载 Excel 文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 MVC 中有一个大的(ish)表单.

I have a large(ish) form in MVC.

我需要能够生成一个包含来自该表单子集的数据的 excel 文件.

I need to be able to generate an excel file containing data from a subset of that form.

棘手的一点是这不应该影响表单的其余部分,所以我想通过 AJAX 来完成.我在 SO 上遇到了几个似乎相关的问题,但我不太明白这些答案的含义.

The tricky bit is that this shouldn't affect the rest of the form and so I want to do it via AJAX. I've come across a few questions on SO that seem to be related, but I can't quite work out what the answers mean.

这似乎最接近我所追求的:asp-net-mvc-downloading-excel - 但我不确定我是否理解响应,现在已经有几年了.我还看到了另一篇关于使用 iframe 处理文件下载的文章(再也找不到了),但我不确定如何使用 MVC 来实现这一点.

This one seems the closest to what I'm after: asp-net-mvc-downloading-excel - but I'm not sure I understand the response, and it is a couple years old now. I also came across another article (can't find it anymore) about using an iframe to handle the file download, but I'm not sure how to get this working with MVC.

如果我正在做一个完整的回发,我的 excel 文件返回正常,但我无法在 mvc 中使用 AJAX.

My excel file returns fine if I'm doing a full post back but I can't get it working with AJAX in mvc.

推荐答案

您不能通过 AJAX 调用直接返回要下载的文件,因此另一种方法是使用 AJAX 调用将相关数据发布到您的服务器.然后,您可以使用服务器端代码来创建 Excel 文件(我建议为此使用 EPPlus 或 NPOI,尽管这听起来好像您有这部分工作).

You can't directly return a file for download via an AJAX call so, an alternative approach is to to use an AJAX call to post the related data to your server. You can then use server side code to create the Excel File (I would recommend using EPPlus or NPOI for this although it sounds as if you have this part working).

2016 年 9 月更新

我原来的答案(下面)已经超过 3 年了,所以我想我会更新,因为我在通过 AJAX 下载文件时不再在服务器上创建文件但是,我留下了原来的答案,因为它可能会有用仍然取决于您的具体要求.

My original answer (below) was over 3 years old, so I thought I would update as I no longer create files on the server when downloading files via AJAX however, I have left the original answer as it may be of some use still depending on your specific requirements.

我的 MVC 应用程序中的一个常见场景是通过网页进行报告,该网页具有一些用户配置的报告参数(日期范围、过滤器等).当用户指定了他们将它们发布到服务器的参数时,将生成报告(例如作为输出的 Excel 文件),然后我将生成的文件作为字节数组存储在 TempData 存储桶中具有独特的参考.此引用作为 Json 结果传递回我的 AJAX 函数,该函数随后重定向到单独的控制器操作以从 TempData 提取数据并下载到最终用户浏览器.

A common scenario in my MVC applications is reporting via a web page that has some user configured report parameters (Date Ranges, Filters etc.). When the user has specified the parameters they post them to the server, the report is generated (say for example an Excel file as output) and then I store the resulting file as a byte array in the TempData bucket with a unique reference. This reference is passed back as a Json Result to my AJAX function that subsequently redirects to separate controller action to extract the data from TempData and download to the end users browser.

为了提供更多细节,假设您有一个具有绑定到模型类的表单的 MVC 视图,让我们调用模型 ReportVM.

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 调用如下所示:

The AJAX call that posts my MVC form to the above controller and receives the response looks like this:

$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();
   }
}

如果需要,可以轻松适应的另一个更改是将文件的 MIME 类型作为第三个参数传递,以便一个 Controller 操作可以正确地提供各种输出文件格式.

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.

注意,使用TempData 而不是Session 的好处是,一旦TempData 被读取,数据就会被清除,所以效率会更高如果您有大量文件请求,则在内存使用方面.请参阅临时数据最佳实践.

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.

原始答案

您不能通过 AJAX 调用直接返回要下载的文件,因此另一种方法是使用 AJAX 调用将相关数据发布到您的服务器.然后,您可以使用服务器端代码来创建 Excel 文件(我建议为此使用 EPPlus 或 NPOI,尽管这听起来好像您已经完成了这部分工作).

You can't directly return a file for download via an AJAX call so, an alternative approach is to to use an AJAX call to post the related data to your server. You can then use server side code to create the Excel File (I would recommend using EPPlus or NPOI for this although it sounds as if you have this part working).

在服务器上创建文件后,将文件路径(或仅文件名)作为返回值传递给 AJAX 调用,然后将 JavaScript window.location 设置为此将提示浏览器下载文件的 URL.

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 调用的简单人为示例:

Below is a simple contrived example of an ajax call to achieve this:

$.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 命令重定向到实际返回文件以供下载的控制器/操作方法.
    • url parameter is the Controller/Action method where your code will create the Excel file.
    • data parameter contains the json data that would be extracted from the form.
    • returnValue would be the file name of your newly created Excel file.
    • The window.location command redirects to the Controller/Action method that actually returns your file for download.
    • 下载操作的示例控制器方法是:

      A sample controller method for the Download action would be:

      [HttpGet]
      public virtual ActionResult Download(string file)
      {   
        string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
        return File(fullPath, "application/vnd.ms-excel", file);
      }
      

      这篇关于通过 AJAX MVC 下载 Excel 文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆