Download Excel file via AJAX MVC

后端 未结 14 1772
说谎
说谎 2020-11-22 02:30

I have a large(ish) form in MVC.

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

The tricky bit is that this shouldn

14条回答
  •  [愿得一人]
    2020-11-22 03:03

    The accepted answer didn't quite work for me as I got a 502 Bad Gateway result from the ajax call even though everything seemed to be returning fine from the controller.

    Perhaps I was hitting a limit with TempData - not sure, but I found that if I used IMemoryCache instead of TempData, it worked fine, so here is my adapted version of the code in the accepted answer:

    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 call remains as with the accepted answer (I made no changes):

    $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 (_cache.Get(fileGuid) != null)
        {
            byte[] data = _cache.Get(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
        }
    }
    

    ...

    Now there is some extra code for setting up MemoryCache...

    In order to use "_cache" I injected in the constructor for the controller like so:

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

    And make sure you have the following in ConfigureServices in Startup.cs:

    services.AddDistributedMemoryCache();
    

提交回复
热议问题