generate csv from mvc web api httpresponse and receive it by angularjs for download

流过昼夜 提交于 2019-12-05 13:35:40

Forgot to update this, but i now found a way to solve this:

There will be two API's, one (POST) will remember the data to be used in the processing and another one (GET) which will dispense the file.

POST:

    [HttpPost]
    public async Task<HttpResponseMessage> BuildFile(FileParameters fileParams)
    {
        var guid = Guid.NewGuid().ToString();
        if (fileParams!= null)
        {
            await Task.Run(() => FileContents.Add(guid, fileParams));
            return this.Request.CreateResponse(HttpStatusCode.OK, new { Value = guid });
        }
        return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid data");
    }

In AngularJs, remember the guid returned and pass this to another api:

 location.href = '/api/file/generatefile' + '?guid=' + generatedGuidFromAPI + '&reportName=' + $scope.reportName;

And here is the generatefile API controller in MVC:

GET:

  [HttpGet]
    public async Task<HttpResponseMessage> GenerateFile(string guid, string reportName)
    {
        byte[] output = null;
        if (FileContents.ContainsKey(guid))
        {
            await Task.Run(() =>
            {
                using (var stream = new MemoryStream())
                {
                    this.CreateFile(FileContents[guid], stream);
                    stream.Flush();
                    output = stream.ToArray();
                }
            });
        }

        FileContents.Remove(guid);
        if (output != null)
        {
            var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(output) };
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = reportName + ".csv"
            };
            return result;
        }

        return this.Request.CreateErrorResponse(HttpStatusCode.NoContent, "No record found");
    }

using location.href will cause the browser to automatically download the file, asking you whether to save it or not.

Here's how I do it: (tested in chrome)

    // WebAPI controller action
    public IHttpActionResult Get(string rpt, DateTime date)
    {
        List<DailyMIReportViewModel> list = new List<DailyMIReportViewModel>();

        // Do some stuff to generate list of items

        // Download Requested
        if (rpt == "dailymidl")
        {
            // Create byte array of csv
            byte[] csvData = WriteCsvWithHeaderToMemory(list);
            // create FileContentResult of cdv byte array
            FileContentResult result = new FileContentResult(csvData, "application/octet-stream");
            // set filename in FileContentResult
            result.FileDownloadName = "Report.csv";

            return Ok(result);
        }
        // Data Requested
        return Ok(list);

        // Client-side angularjs
        // Called on button click
        $scope.generateMIDownload = function (forDate) {
            // Using $resource to return promise with FileContentResult payload
            reportsRepository.dailymidl(forDate).$promise.then(
            function (data) {
                //ok
                // NOTE: the base64 part is what got it working

                var dataUrl = 'data:application/octet-stream;base64,' + data.FileContents
                var link = document.createElement('a');
                angular.element(link)
                  .attr('href', dataUrl)
                  .attr('download', data.FileDownloadName)
                  .attr('target','_blank')
                link.click();
            },
            function (response) {
                //not ok
            });
        }

        // Reports Repository (for ref)
        angular.module('msgnr').factory('reportsRepository', function ($resource) {
            return {
                dailymidl: function (date) {
                    return $resource('/api/Report/', { rpt: 'dailymidl', date: date, toDate: date }).get();
            }
        }
    });

Incase it helps anyone else.

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