通过AJAX MVC下载Excel文件

时间:2013-05-21 12:37:39

标签: c# jquery asp.net-mvc vb.net export-to-excel

我在MVC中有一个大(ish)形式。

我需要能够生成包含该表单子集中数据的excel文件。

棘手的一点是,这不应该影响表单的其余部分,所以我想通过AJAX来做。我在SO上遇到了几个似乎相关的问题,但我无法弄清楚答案的意思。

这个似乎与我之后的最接近:asp-net-mvc-downloading-excel - 但我不确定我是否理解这一反应,现在已经有几年了。我还发现了另一篇关于使用iframe处理文件下载的文章(暂时无法找到),但我不确定如何使用MVC。

如果我做了一个完整的帖子,我的excel文件会很好,但是我无法在mvc中使用AJAX。

14 个答案:

答案 0 :(得分:177)

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

  

2016年9月更新

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

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

为了给出更多细节,假设你有一个MVC View,它有一个绑定到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类型作为第三个参数传递,以便一个Controller操作可以正确地提供各种输出文件格式。

这消除了在服务器上创建和存储任何物理文件的任何需要,因此不需要管理例程,并且这对于最终用户来说是无缝的。

注意,使用TempData而不是Session的优点是,一旦读取TempData,数据就会被清除,因此如果你有一个内存使用,它会更有效率大量的文件请求。请参阅TempData Best Practice

  

原始回答

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

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

从最终用户的角度来看,文件下载操作是无缝的,因为它们永远不会离开请求所在的页面。

下面是一个简单的人为调用实例的例子:

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

答案 1 :(得分:19)

我的2美分 - 您不需要将Excel作为物理文件存储在服务器上 - 而是将其存储在(会话)缓存中。为Cache变量(存储该excel文件)使用唯一生成的名称 - 这将是(初始)ajax调用的返回。这样您就不必处理文件访问问题,在不需要时管理(删除)文件等等,并且将文件放入缓存中,检索它的速度会更快。

答案 2 :(得分:12)

我最近能够在MVC中完成此任务(尽管没有必要使用AJAX)而不创建物理文件并且认为我会分享我的代码:

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

function getWinnersExcel(drawingId) {
    window.location = "/drawing/drawingwinnersexcel?drawingid=" + drawingId;
}

C#控制器代码:

    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中,浏览器会提示下载文件,但不会进行实际导航。

答案 3 :(得分:6)

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

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

我已经从CSL更新了serer端代码,而不是使用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();
   }
}

答案 4 :(得分:6)

首先创建将创建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;
    }
});

答案 5 :(得分:0)

这个帖子帮我创建了自己的解决方案,我将在这里分享。我一开始就使用了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");
    }

答案 6 :(得分:0)

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

答案 7 :(得分:0)

使用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);
    }

答案 8 :(得分:0)

$.ajax({
                type: "GET",
                url: "/Home/Downloadexcel/",
                contentType: "application/json; charset=utf-8",
                data: null,
                success: function (Rdata) {
                    debugger;
                    var bytes = new Uint8Array(Rdata.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 (err) {

                }

            });

答案 9 :(得分:0)

被接受的答案对我来说并不奏效,因为从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
    }
}

...

现在有一些额外的代码可用于设置MemoryCache ...

为了使用“ _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();

答案 10 :(得分:0)

我听起来可能很幼稚,可能引起了很多批评,但这是我的做法,

它不涉及 export ajax ,但不会执行完整回发 两个

感谢this的帖子和this的答案。

创建一个简单的控制器

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 another action,(GetFilteredPartial() illustrated below )
     when searching for the data,
     so do not really need ajax here..to pass my filters.. */

 var dt = Utility.ConvertToDataTable(someList); //Some utility to convert list to Datatable

        //  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);
    } */     
} 

这是视图。.或视图

/* @model Models.MainViewModel
 @{
   ViewBag.Title = "Home Page";
   Layout = "~/Views/Shared/_Layout.cshtml";
  }

   <div class="main-container">... 
          Some code for, say, a partial View  
              <div id="tblSampleBody">
                @Html.Partial("_SomePartialView", Model.PartialViewModel)
              </div>
  */                                                       
//The actual part.. Just post this bit of data... Here, you are not posting the Main form.. 
        @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视图的 mid 中发布一个表单,调用是一种Action方法,返回 FileResult ,然后在返回中返回 File 要发布过滤器值(如您所说),(如果需要的话),我将它们发布到另一个动作中,正如我们试图描述的那样。

答案 11 :(得分:0)

  $.ajax({
    global: false,
    url: SitePath + "/User/ExportTeamMembersInExcel",
    "data": { 'UserName': UserName, 'RoleId': RoleId, UserIds: AppraseeId },
    "type": "POST",
    "dataType": "JSON",
   "success": function (result) {
        debugger
        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);
    }

答案 12 :(得分:-1)

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

那是我的问题。

我必须在运行时动态创建大量输入按钮。我想添加每个按钮以下载按钮,并给出一个唯一的fileNumber。

我按这样创建每个按钮:

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

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

&#13;
&#13;
$.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;
    }
});
&#13;
&#13;
&#13;

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

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

我正在生成此Form_1,Form_2,Form_3 ....我将用另一个程序删除这些旧文件。但是,如果有一种方法可以像使用Response一样将字节数组发送到下载文件。我想用它。

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

答案 13 :(得分:-1)

提交表格

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