How to properly create and download a dynamically generated binary *.xlsx file on .net MVC4?

ぐ巨炮叔叔 提交于 2019-12-10 11:45:35

问题


I need to make an 'export to excel' feature.

Excel is a binary file, and it sends a warning on msExcel if you use its XML format.

What i'm currently doing is keeping a state object (since i need to be aware of the various changes a user is making) with all my data and passing it to a .net MVC controller using ajax, which uses a library to create the *.xlsx file.

client side:

 $.ajax({
    type: "POST",
    url: "/path/to/exportController",
    data: exporter.getData(),
    success: success,
    error: error,
    dataType: 'json'
 });

Server side:

 public ActionResult Excel(mySpecialandIrrelevantDescriptiveClass jsonData)
    {
      //excel generation logic
      .....
    }

Now from the way i see it, i got 3 options here:

  1. Create a stream and push it back to the ajax request - but from what i've gathered, ajax can't really push for a download request with a generated binary stream

  2. save the file on the servers hard-drive, return a public url for it and open a new popup window with the new URL, get the download prompt and somehow close the window so it wouldn't look ugly.

  3. forget about the ajax, push everything into some hidden form fields and post it to the server, again opening a new window and wait for the response , then closing it.

option #2 will require me to create a task that will constantly purge the generated files and URLs which is a huge hassle since the platform will get about 10-20k hits for this feature alone.

What's the best way to achieve what i need?


回答1:


So this is how i eventually got it :

You can't use ajax to return a binary file - you'll receive its data - but will have no way of manifesting the binary file

I've used EPPlus as the excel library and passed the data through a post method within generic HTML form hidden fields. The output was generated using a stream as the return value thus keeping the user on the page without refreshes/redirects

Server:

//the expected data description - automatic tool @ http://json2csharp.com/
public class ExpectedJSON
{
    public class SomeDataSet
    {
        public string dude{ get; set; }
        public string what { get; set; }
        public string foo { get; set; }
        public string bar { get; set; }
        public string baz { get; set; }
        public int asd { get; set; }
        public string someDate { get; set; }
        public string wat { get; set; }
        public string grrr { get; set; }
    }

    public class AnotherDataSet
    {
        public int type { get; set; }
        public string date { get; set; }
        public string dancing { get; set; }
        public double camels { get; set; }
        public int are { get; set; }
        public int crying { get; set; }
        public double _for { get; set; }
        public double some { get; set; }
        public double beer { get; set; }
    }

    public class MoreData
    {
        public int dark { get; set; }
        public double side { get; set; }
        public int of { get; set; }
        public int the { get; set; }
        public double moon { get; set; }
        public double iz { get; set; }
        public double da { get; set; }
        public string bomb { get; set; }
    }
}

public class ExportToController : Controller
{
    public ActionResult Excel([FromUri(Name= "someData")] string someDataSet,
                              [FromUri(Name = "anotherData")] string anotherDataSet,
                              [FromUri(Name = "moreData")] string moreData)
    {
        ExpectedJSON.SomeDataSet someDataSetJson = JsonConvert.DeserializeObject<ExpectedJSON.SomeDataSet>(someData);
        ExpectedJSON.AnotherDataSet[] anotherDataSetJson = JsonConvert.DeserializeObject<Campaign.OnlineComulativeDailyBuildChart[]>(anotherData);
        ExpectedJSON.MoreData[] moreDataJson = JsonConvert.DeserializeObject<Campaign.OnlineSitesGrid[]>(moreData);
        string fileName = "file.xlsx";

        ExcelPackage p = new ExcelPackage();
        p.Workbook.Worksheets.Add("Some Sheet");
        ExcelWorksheet ws = p.Workbook.Worksheets[1];

        //excel library logic follows...

        //...
        //..


       //stream logic

        MemoryStream stream = new MemoryStream(p.GetAsByteArray());


        FileStreamResult result = new FileStreamResult(stream, "application/vnd.ms-excel")
        {
            FileDownloadName = fileName
        };

        return result;
    }
}

HTML:

<form id="exportToExcel" action="../ExportTo/Excel/" target="_blank" method="post">
  <input type="hidden" id="someData" name="someData" />
  <input type="hidden" id="anotherData" name="anotherData" />
  <input type="hidden" id="moreData" name="moreData" />
  <button type="submit">export</button>
</form>

All my data components (which needed to be exported) sign their data objects into a generic object so that on submit - the value attribute is populated with the json representation of it using JSON.stringify:

function bindEvents() {
    var exportForm = $("#exportToExcel");
    var someData= exportForm.find("#someData");
    var anotherData= exportForm.find("#anotherData");
    var moreData = exportForm.find("#moreData");
    exportForm.on('submit', function (e) {
        someData.attr("value", JSON.stringify(exporter.getData().someData));
        anotherData.attr("value", JSON.stringify(exporter.getData().anotherData));
        moreData .attr("value", JSON.stringify(exporter.getData().moreData));
    });
}

Minutes with rails/sinatra/nodeJS - days/weeks with .net - but there you have it.




回答2:


The are tons of questions like this:

  • JavaScript/jQuery to download file via POST with JSON data
  • jQuery UI Dialog calling action that returns an HttpContect response stream in MVC 3
  • Handle file download from ajax post
  • Download file from Ajax (sort of)
  • Downloading file though AJAX POST
  • Download a file with an ajax call
  • Getting a downloadable file with an ajax request
  • Generating file with ajax and allow user to download it?
  • How to allow download of file, that is returned as binary data from AJAX

I could go on with this :)

Bottom line they all suggest using some kind of redirection through a <form>, an <iframe> or window.location.

This is probably the way to go, however if you're feeling adventurous enough I would also try some combination of HTML5 Blob API, File System and/or Typed Arrays.



来源:https://stackoverflow.com/questions/19684442/how-to-properly-create-and-download-a-dynamically-generated-binary-xlsx-file-o

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!