Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return an Excel file from ASP.NET Core Web API web-app?

In similar questions, with this code works to download a PDF:

I'm testing with local files (.xlsx, .pdf, .zip) inside the Controller folder.

Similar Question Here

[HttpGet("downloadPDF")]
public FileResult TestDownloadPCF()
{
   HttpContext.Response.ContentType = "application/pdf";
   FileContentResult result = new FileContentResult
   (System.IO.File.ReadAllBytes("Controllers/test.pdf"), "application/pdf")
    {
      FileDownloadName = "test.pdf"
    };
   return result;
}

This works great!

But when another file?, for example an Excel File(.xlsx) or ZIP File(.zip), testing does not work properly.

Code :

[HttpGet("downloadOtherFile")]
public FileResult TestDownloadOtherFile()
{
  HttpContext.Response.ContentType = 
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  FileContentResult result = new FileContentResult(System.IO.File.ReadAllBytes("Controllers/test.xlsx"), 
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
  {
    FileDownloadName = "otherfile"
   };
  return result;
}

Result: enter image description here

I also did tests with the following Content-Type:

  • "Application / vnd.ms-excel"
  • "Application / vnd.ms-excel.12"

Getting the same result.

Which is the right way to return any file type?

Thanks for your answers

like image 707
Jose Eduardo Poma Caceres Avatar asked Aug 10 '16 15:08

Jose Eduardo Poma Caceres


2 Answers

My (working) solution:

  • I've got a class that dynamically creates an XLSX file using EPPlus.Core.
    • This returns a FileInfo for the generated file's path.

This is what is in my Controller:

[HttpGet("test")]
public async Task<FileResult> Get()
{
    var contentRootPath = _hostingEnvironment.ContentRootPath;

    // "items" is a List<T> of DataObjects
    var items = await _mediator.Send(new GetExcelRequest());

    var fileInfo = new ExcelFileCreator(contentRootPath).Execute(items);
    var bytes = System.IO.File.ReadAllBytes(fileInfo.FullName);

    const string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    HttpContext.Response.ContentType = contentType;
    HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");

    var fileContentResult = new FileContentResult(bytes, contentType)
    {
        FileDownloadName = fileInfo.Name
    };

    return fileContentResult;
}

And here is what I have in Angular2:

downloadFile() {
    debugger;
    var headers = new Headers();
    headers.append('responseType', 'arraybuffer');

    let url = new URL('api/excelFile/test', environment.apiUrl);

    return this.http
        .get(url.href, {
            withCredentials: true,
            responseType: ResponseContentType.ArrayBuffer
        })
        .subscribe((response) => {
            let file = new Blob([response.blob()], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
            let fileName = response.headers.get('Content-Disposition').split(';')[1].trim().split('=')[1];
            saveAs(file, fileName);
        },
        err => this.errorHandler.onError(err)
        );
}
like image 160
BCdotWEB Avatar answered Sep 18 '22 17:09

BCdotWEB


I had this same issue. My issue was being caused by the client request, not the server response. I solved it by adding a response content type to my Get request's header options. Here is my example in Angular 2.

Request from client (Angular 2) **requires filesaver.js library

this._body = '';

    let rt: ResponseContentType = 2; // This is what I had to add ResponseContentType (2 = ArrayBuffer , Blob = 3)
        options.responseType = rt;
    if (url.substring(0, 4) !== 'http') {
        url = config.getApiUrl(url);
    }

    this.http.get(url, options).subscribe(
        (response: any) => {
            let mediaType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
            let blob = new Blob([response._body], { type: mediaType });
            let filename = 'test.xlsx';
            fileSaver.saveAs(blob, filename);
        });

Server side code. (.net core)

    [HttpGet("{dataViewId}")]
    public IActionResult GetData(string dataViewId)
    {
        var fileName = $"test.xlsx";
        var filepath = $"controllers/test/{fileName}";
        var mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        byte[] fileBytes = System.IO.File.ReadAllBytes(filepath);
        return File(fileBytes, mimeType, fileName);
    }

here are the references if you want to see.

Corrupted download in AngularJs app

C# File Download is Corrupt

like image 39
Jay Culpepper Avatar answered Sep 21 '22 17:09

Jay Culpepper