通过AJAX MVC下载Excel文件

本文关键字:Excel 文件 下载 MVC AJAX 通过 | 更新日期: 2023-09-27 18:14:30

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

我需要能够生成一个excel文件包含从该形式的子集的数据。

棘手的一点是,这应该不会影响表单的其余部分,所以我想通过AJAX来做到这一点。我遇到了一些关于SO的问题,似乎是相关的,但我不太清楚答案是什么意思。

这个似乎最接近我所追求的:asp-net-mvc-download -excel -但我不确定我理解的反应,它是几年前的了。我还遇到了另一篇文章(找不到它了),关于使用iframe来处理文件下载,但我不确定如何与MVC一起工作。

我的excel文件返回很好,如果我做一个完整的帖子回来,但我不能得到它与AJAX在mvc工作。

通过AJAX MVC下载Excel文件

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

UPDATE September 2016

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

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

为了给出更多的细节,假设你有一个MVC视图,窗体绑定到一个模型类,让我们调用模型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调用,然后将JavaScript window.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参数是Controller/Action方法,你的代码将在其中创建Excel文件。
  • data参数包含从表单中提取的json数据。
  • returnValue将是您新创建的Excel文件的文件名。
  • 窗口。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);
}

我的两分意见-你不需要将excel作为物理文件存储在服务器上-相反,将其存储在(Session)缓存中。使用唯一生成的名称为您的缓存变量(存储excel文件)-这将是您的(初始)ajax调用的返回。这样,您就不必处理文件访问问题,在不需要时管理(删除)文件等,并且将文件放在缓存中,可以更快地检索它。

我最近能够在MVC中完成这一点(尽管不需要使用AJAX),而不需要创建物理文件,我认为我应该分享我的代码:

超级简单的JavaScript函数(datatables.net按钮点击触发此):

function getWinnersExcel(drawingId) {
    window.location = "/drawing/drawingwinnersexcel?drawingid=" + drawingId;
}
控制器代码:
    public FileResult DrawingWinnersExcel(int drawingId)
    {
        MemoryStream stream = new MemoryStream(); // cleaned up automatically by MVC
        List<DrawingWinner> winnerList = DrawingDataAccess.GetWinners(drawingId); // simple entity framework-based data retrieval
        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文件,它有一个保存到流选项。也就是说,有许多方法可以创建可以轻松写入内存流的Excel文件。

public static class ExportHelper
{
    internal static void GetWinnersAsExcelMemoryStream(MemoryStream stream, List<DrawingWinner> winnerList, int drawingId)
    {
        ExcelFile ef = new ExcelFile();
        // lots of excel worksheet building/formatting code here ...
        ef.SaveXlsx(stream);
        stream.Position = 0; // reset for future read
     }
}

在IE、Chrome和Firefox中,浏览器提示下载文件,没有实际导航。

首先创建将创建Excel文件的控制器动作

[HttpPost]
public JsonResult ExportExcel()
{
    DataTable dt = DataService.GetData();
    var fileName = "Excel_" + DateTime.Now.ToString("yyyyMMddHHmm") + ".xls";
    //save the file to server temp folder
    string fullPath = Path.Combine(Server.MapPath("~/temp"), fileName);
    using (var exportData = new MemoryStream())
    {
        //I don't show the detail how to create the Excel, this is not the point of this article,
        //I just use the NPOI for Excel handler
        Utility.WriteDataTableToExcel(dt, ".xls", exportData);
        FileStream file = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
        exportData.WriteTo(file);
        file.Close();
    }
    var errorMessage = "you can return the errors in here!";
    //return the Excel file name
    return Json(new { fileName = fileName, errorMessage = "" });
}
然后创建下载操作
[HttpGet]
[DeleteFileAttribute] //Action Filter, it will auto delete the file after download, 
                      //I will explain it later
public ActionResult Download(string file)
{
    //get the temp folder and file path in server
    string fullPath = Path.Combine(Server.MapPath("~/temp"), file);
    //return the file for download, this is an Excel 
    //so I set the file content type to "application/vnd.ms-excel"
    return File(fullPath, "application/vnd.ms-excel", file);
}

如果你想在下载后删除文件,创建这个

public class DeleteFileAttribute : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        filterContext.HttpContext.Response.Flush();
        //convert the current filter context to file and get the file path
        string filePath = (filterContext.Result as FilePathResult).FileName;
        //delete the file after download
        System.IO.File.Delete(filePath);
    }
}

,最后ajax调用MVC Razor视图

//I use blockUI for loading...
$.blockUI({ message: '<h3>Please wait a moment...</h3>' });    
$.ajax({
    type: "POST",
    url: '@Url.Action("ExportExcel","YourController")', //call your controller and action
    contentType: "application/json; charset=utf-8",
    dataType: "json",
}).done(function (data) {
    //console.log(data.result);
    $.unblockUI();
    //get the file name for download
    if (data.fileName != "") {
        //use window.location.href for redirect to download action for download the file
        window.location.href = "@Url.RouteUrl(new 
            { Controller = "YourController", Action = "Download"})/?file=" + data.fileName;
    }
});

我使用了CSL发布的解决方案,但我建议您不要在整个会话期间将文件数据存储在会话中。通过使用TempData,在下一个请求(即对文件的GET请求)之后自动删除文件数据。您还可以在下载操作中管理会话中文件数据的删除。

会话可能会消耗很多内存/空间,这取决于SessionState存储和会话期间导出的文件数量,以及是否有很多用户。

我已经从CSL更新了服务器端代码,使用TempData代替。

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

using ClosedXML.Excel;

   public ActionResult Downloadexcel()
    {   
        var Emplist = JsonConvert.SerializeObject(dbcontext.Employees.ToList());
        DataTable dt11 = (DataTable)JsonConvert.DeserializeObject(Emplist, (typeof(DataTable)));
        dt11.TableName = "Emptbl";
        FileContentResult robj;
        using (XLWorkbook wb = new XLWorkbook())
        {
            wb.Worksheets.Add(dt11);
            using (MemoryStream stream = new MemoryStream())
            {
                wb.SaveAs(stream);
                var bytesdata = File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "myFileName.xlsx");
                robj = bytesdata;
            }
        }

        return Json(robj, JsonRequestBehavior.AllowGet);
    }

. ajax({美元类型:"获得",url:"/Home/Downloadexcel/",contentType:"application/json;charset = utf - 8",数据:空,成功:函数(Rdata) {调试器;var bytes = new Uint8Array(Rdata.FileContents);var blob =新的blob ([bytes],{类型:"application/vnd.openxmlformats-officedocument.spreadsheetml. var blob = "表"});var link = document.createElement('a');链接。href = window.URL.createObjectURL(blob);链接。download = "myFileName.xlsx";link.click ();},错误:function (err) {}});
  $.ajax({
    global: false,
    url: SitePath + "/User/ExportTeamMembersInExcel",
    "data": { 'UserName': UserName, 'RoleId': RoleId, UserIds: AppraseeId },
    "type": "POST",
    "dataType": "JSON",
   "success": function (result) {
        
        var bytes = new Uint8Array(result.FileContents);
        var blob = new Blob([bytes], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
        var link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = "myFileName.xlsx";
        link.click();
      },
    "error": function () {
        alert("error");
    }
})

[HttpPost]
    public JsonResult ExportTeamMembersInExcel(string UserName, long? RoleId, string[] UserIds)
    {
        MemoryStream stream = new MemoryStream();
        FileContentResult robj;
        DataTable data = objuserservice.ExportTeamToExcel(UserName, RoleId, UserIds);
        using (XLWorkbook wb = new XLWorkbook())
        {
            wb.Worksheets.Add(data, "TeamMembers");
            using (stream)
            {
                wb.SaveAs(stream);
            }
        }
        robj = File(stream.ToArray(), System.Net.Mime.MediaTypeNames.Application.Octet, "TeamMembers.xlsx");
        return Json(robj, JsonRequestBehavior.AllowGet);
    }

接受的答案不太适合我,因为我从ajax调用中得到了502坏网关结果,即使一切似乎都从控制器返回良好。

也许我遇到了TempData的限制-不确定,但我发现,如果我使用IMemoryCache而不是TempData,它工作得很好,所以这里是我在接受的答案中改编的代码版本:

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();
        //This is an equivalent to tempdata, but requires manual cleanup
        _cache.Set(handle, memoryStream.ToArray(), 
                    new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(10))); 
                    //(I'd recommend you revise the expiration specifics to suit your application)
   }      
   // Note we are returning a filename as well as the handle
   return new JsonResult() { 
         Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
   };
}

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 (_cache.Get<byte[]>(fileGuid) != null)
    {
        byte[] data = _cache.Get<byte[]>(fileGuid);
        _cache.Remove(fileGuid); //cleanup here as we don't need it in cache anymore
        return File(data, "application/vnd.ms-excel", fileName);
    }
    else
    {
        // Something has gone wrong...
        return View("Error"); // or whatever/wherever you want to return the user
    }
}

现在有一些额外的代码来设置内存缓存…

为了使用"_cache",我像这样在控制器的构造函数中注入:

using Microsoft.Extensions.Caching.Memory;
namespace MySolution.Project.Controllers
{
 public class MyController : Controller
 {
     private readonly IMemoryCache _cache;
     public LogController(IMemoryCache cache)
     {
        _cache = cache;
     }
     //rest of controller code here
  }
 }

并确保在Startup.cs中的ConfigureServices中有以下配置:

services.AddDistributedMemoryCache();

我可能听起来很天真,可能会招致很多批评,但我是这样做的,
(它不涉及 ajax 的导出,但它不做一个完整的回发)

感谢这个帖子和这个回答。
创建简单控制器

public class HomeController : Controller
{               
   /* A demo action
    public ActionResult Index()
    {           
        return View(model);
    }
   */
    [HttpPost]
    public FileResult ExportData()
    {
        /* An example filter
        var filter = TempData["filterKeys"] as MyFilter;
        TempData.Keep();            */
        var someList = db.GetDataFromDb(/*filter*/) // filter as an example
    /*May be here's the trick, I'm setting my filter in TempData["filterKeys"] 
     in an action,(GetFilteredPartial() illustrated below) when 'searching' for the data,
     so do not really need ajax here..to pass my filters.. */
     //Some utility to convert list to Datatable
     var dt = Utility.ConvertToDataTable(someList); 
      //  I am using EPPlus nuget package 
      using (ExcelPackage pck = new ExcelPackage())
      {
          ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Sheet1");
          ws.Cells["A1"].LoadFromDataTable(dt, true);
            using (var memoryStream = new MemoryStream())
            {                   
              pck.SaveAs(memoryStream);
              return File(memoryStream.ToArray(),
              "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
              "ExportFileName.xlsx");                    
            }                
        }   
    }
    //This is just a supporting example to illustrate setting up filters ..        
   /* [HttpPost]
    public PartialViewResult GetFilteredPartial(MyFilter filter)
    {            
        TempData["filterKeys"] = filter;
        var filteredData = db.GetConcernedData(filter);
        var model = new MainViewModel();
        model.PartialViewModel = filteredData;
        return PartialView("_SomePartialView", model);
    } */     
} 

这里是Views.

/*Commenting out the View code, in order to focus on the imp. code     
 @model Models.MainViewModel
 @{Layout...}     
      Some code for, say, a partial View  
      <div id="tblSampleBody">
        @Html.Partial("_SomePartialView", Model.PartialViewModel)
      </div>
  */                                                       
//The actual part.. Just **posting** this bit of data from the complete View...
//Here, you are not posting the full Form..or the complete View
   @using (Html.BeginForm("ExportData", "Home", FormMethod.Post))
    {
        <input type="submit" value="Export Data" />
    }
//...
//</div>
/*And you may require to pass search/filter values.. as said in the accepted answer..
That can be done while 'searching' the data.. and not while
 we need an export..for instance:-             
<script>             
  var filterData = {
      SkipCount: someValue,
      TakeCount: 20,
      UserName: $("#UserName").val(),
      DepartmentId: $("#DepartmentId").val(),     
   }
  function GetFilteredData() {
       $("#loader").show();
       filterData.SkipCount = 0;
       $.ajax({
          url: '@Url.Action("GetFilteredPartial","Home")',
          type: 'POST',
          dataType: "html",
          data: filterData,
          success: function (dataHTML) {
          if ((dataHTML === null) || (dataHTML == "")) {
              $("#tblSampleBody").html('<tr><td>No Data Returned</td></tr>');
                $("#loader").hide();
            } else {
                $("#tblSampleBody").html(dataHTML);                    
                $("#loader").hide();
            }
        }
     });
   }    
</script>*/
技巧的全部要点似乎是,我们发布了一个表单(Razor View的部分),我们调用Action method,它返回:一个 FileResult ,而这个 FileResult 返回 the Excel File
对于发布过滤器值,如前所述,(如果您需要),我正在向另一个动作发出post请求,正如已经尝试描述的那样…

这对我有用。确保从控制器动作返回一个文件,内容类型为"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";和文件名,例如"List.xlsx"这应该与AJAX成功调用中的相同。我使用了ClosedXML NuGet包来生成excel文件。

$.ajax({
    url: "Home/Export",
    type: 'GET',      
    contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    xhrFields: { responseType: 'blob' },
    success: function (data) {
        var a = document.createElement('a');
        var url = window.URL.createObjectURL(data);
        a.href = url;
        a.download = 'List.xlsx';
        a.click();
        window.URL.revokeObjectURL(url);
    }
});

这个帖子帮助我创建了我自己的解决方案,我将在这里分享。我一开始使用的是GET ajax请求,没有问题,但它到了一个点,请求URL长度超过了,所以我不得不切换到POST。

javascript使用JQuery文件下载插件,由2个后续调用组成。一个POST(发送参数)和一个GET(获取文件)。

 function download(result) {
        $.fileDownload(uri + "?guid=" + result,
        {
            successCallback: onSuccess.bind(this),
            failCallback: onFail.bind(this)
        });
    }
    var uri = BASE_EXPORT_METADATA_URL;
    var data = createExportationData.call(this);
    $.ajax({
        url: uri,
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify(data),
        success: download.bind(this),
        fail: onFail.bind(this)
    });
服务器端

    [HttpPost]
    public string MassExportDocuments(MassExportDocumentsInput input)
    {
        // Save query for file download use
        var guid = Guid.NewGuid();
        HttpContext.Current.Cache.Insert(guid.ToString(), input, null, DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration);
        return guid.ToString();
    }
   [HttpGet]
    public async Task<HttpResponseMessage> MassExportDocuments([FromUri] Guid guid)
    {
        //Get params from cache, generate and return
        var model = (MassExportDocumentsInput)HttpContext.Current.Cache[guid.ToString()];
          ..... // Document generation
        // to determine when file is downloaded
        HttpContext.Current
                   .Response
                   .SetCookie(new HttpCookie("fileDownload", "true") { Path = "/" });
        return FileResult(memoryStream, "documents.zip", "application/zip");
    }

CSL的答案是在我正在做的一个项目中实现的,但我遇到的问题是在Azure上扩展导致我们的文件下载中断。相反,我可以通过一个AJAX调用来实现:

服务器

[HttpPost]
public FileResult DownloadInvoice(int id1, int id2)
{
    //necessary to get the filename in the success of the ajax callback
    HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
    byte[] fileBytes = _service.GetInvoice(id1, id2);
    string fileName = "Invoice.xlsx";
    return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}

(修改版本的Handle file download from ajax post)

$("#downloadInvoice").on("click", function() {
    $("#loaderInvoice").removeClass("d-none");
    var xhr = new XMLHttpRequest();
    var params = [];
    xhr.open('POST', "@Html.Raw(Url.Action("DownloadInvoice", "Controller", new { id1 = Model.Id1, id2 = Model.Id2 }))", true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function () {
        if (this.status === 200) {
            var filename = "";
            var disposition = xhr.getResponseHeader('Content-Disposition');
            if (disposition && disposition.indexOf('attachment') !== -1) {
                var filenameRegex = /filename[^;='n]*=((['"]).*?'2|[^;'n]*)/;
                var matches = filenameRegex.exec(disposition);
                if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
            }
            var type = xhr.getResponseHeader('Content-Type');
            var blob = typeof File === 'function'
                ? new File([this.response], filename, { type: type })
                : new Blob([this.response], { type: type });
            if (typeof window.navigator.msSaveBlob !== 'undefined') {
                // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
                window.navigator.msSaveBlob(blob, filename);
            } else {
                var URL = window.URL || window.webkitURL;
                var downloadUrl = URL.createObjectURL(blob);
                if (filename) {
                    // use HTML5 a[download] attribute to specify filename
                    var a = document.createElement("a");
                    // safari doesn't support this yet
                    if (typeof a.download === 'undefined') {
                        window.location = downloadUrl;
                    } else {
                        a.href = downloadUrl;
                        a.download = filename;
                        document.body.appendChild(a);
                        a.click();
                    }
                } else {
                    window.location = downloadUrl;
                }
                setTimeout(function() {
                        URL.revokeObjectURL(downloadUrl);
                    $("#loaderInvoice").addClass("d-none");
                }, 100); // cleanup
            }
        }
    };
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send($.param(params));
});

我使用Asp。Net WebForm,我想从服务器端下载一个文件。有很多文章,但我找不到基本的答案。现在,我尝试了一个基本的方法,并得到了它。

这就是我的问题。

我必须在运行时动态地创建很多输入按钮。我想给每个按钮添加一个唯一的fileNumber。

我这样创建每个按钮:

fragment += "<div><input type='"button'" value='"Create Excel'" onclick='"CreateExcelFile(" + fileNumber + ");'" /></div>";

每个按钮调用这个ajax方法。

$.ajax({
    type: 'POST',
    url: 'index.aspx/CreateExcelFile',
    data: jsonData,
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function (returnValue) {
      window.location = '/Reports/Downloads/' + returnValue.d;
    }
});

然后我写了一个基本的简单方法

[WebMethod]
public static string CreateExcelFile2(string fileNumber)
{
    string filePath = string.Format(@"Form_{0}.xlsx", fileNumber);
    return filePath;
}

生成Form_1, Form_2, Form_3....我要用另一个程序删除这些旧文件。但如果有一种方法可以发送字节数组来下载文件,比如使用Response。我想用它

我希望这对任何人都有用。

提交形式

public ActionResult ExportXls()
{   
 var filePath="";
  CommonHelper.WriteXls(filePath, "Text.xls");
}
 public static void WriteXls(string filePath, string targetFileName)
    {
        if (!String.IsNullOrEmpty(filePath))
        {
            HttpResponse response = HttpContext.Current.Response;
            response.Clear();
            response.Charset = "utf-8";
            response.ContentType = "text/xls";
            response.AddHeader("content-disposition", string.Format("attachment; filename={0}", targetFileName));
            response.BinaryWrite(File.ReadAllBytes(filePath));
            response.End();
        }
    }