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

后端 未结 4 1684
情话喂你
情话喂你 2020-12-31 09:47

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

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

相关标签:
4条回答
  • 2020-12-31 10:26

    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

    0 讨论(0)
  • 2020-12-31 10:33

    you can use NPOI

    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc;
    using NPOI.SS.UserModel;
    using NPOI.SS.Util;
    using NPOI.XSSF.UserModel;
    using System.Collections.Generic;
    using System.IO;
    
    namespace export_excel.Controllers
    {
    
        [ApiController]
        [Route("[controller]")]
        public class ExportExcelController : ControllerBase
        {
    
            private readonly IHostingEnvironment _hostingEnvironment;
    
            public ExportExcelController(IHostingEnvironment hostingEnvironment)
            {
                _hostingEnvironment = hostingEnvironment;
            }
    
            // https://localhost:5001/ExportExcel/Export
            // https://localhost:5001/static-file/employee.xlsx
            [HttpGet]
            [Route("Export")]
            public IActionResult Export()
            {
                List<Employee> list = new List<Employee>()
                {
                    new Employee{ emp_code = "152110032", Name = "Nguyen Hong Anh", Phone = "0909998789" },
                    new Employee{ emp_code = "152110055", Name = "Tran Phuong Dung", Phone = "0909993456" },
                    new Employee{ emp_code = "152110022", Name = "Do Bich Ngoc", Phone = "0909991237" },
                    new Employee{ emp_code = "152110025", Name = "Tran Thu Ha", Phone = "0909990987" },
                };
                // New workbook.
                XSSFWorkbook wb = new XSSFWorkbook();
                // New worksheet.
                ISheet sheet = wb.CreateSheet();
                // Write to sheet.
                // Tạo row
                var row0 = sheet.CreateRow(0);
                // At first row, merge 3 columns.
                // Create cell before merging.
                row0.CreateCell(0);
                CellRangeAddress cellMerge = new CellRangeAddress(0, 0, 0, 2);
                sheet.AddMergedRegion(cellMerge);
                row0.GetCell(0).SetCellValue("Employee information");
                // Ghi tên cột ở row 1
                var row1 = sheet.CreateRow(1);
                row1.CreateCell(0).SetCellValue("emp_code");
                row1.CreateCell(1).SetCellValue("fullname");
                row1.CreateCell(2).SetCellValue("Phone");
                // Traversaling array, then write continous.
                int rowIndex = 2;
                foreach (var item in list)
                {
                    // Init new row.
                    var newRow = sheet.CreateRow(rowIndex);
                    // set values.
                    newRow.CreateCell(0).SetCellValue(item.emp_code);
                    newRow.CreateCell(1).SetCellValue(item.Name);
                    newRow.CreateCell(2).SetCellValue(item.Phone);
                    // Increase index.
                    rowIndex++;
                };
                if (!System.IO.File.Exists("c:\\myfiles\\employee.xlsx"))
    
                {
                    FileStream fs = new FileStream(@"c:\myfiles\employee.xlsx", FileMode.CreateNew);
                    wb.Write(fs);
                }
                var path = Path.Combine(@"c:\myfiles\employee.xlsx");
                return File(System.IO.File.OpenRead(path), contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8", fileDownloadName: "employee.xlsx");
            }
    
        }
    
        public class Employee
        {
            public string emp_code;
            public string Name;
            public string Phone;
        }
    
    }
    

    File Startup.cs

    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.FileProviders;
    using Microsoft.Extensions.Hosting;
    using System.IO;
    
    namespace export_excel
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllers();
            }
    
            public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                app.UseHttpsRedirection();
                app.UseRouting();
                app.UseAuthorization();
                app.UseStaticFiles(new StaticFileOptions
                {
                    FileProvider = new PhysicalFileProvider(
                // Path.Combine(env.ContentRootPath, @"c:\audio\")),
                // Path.Combine(@"c:\audio\")),
                Path.Combine(@"c:\myfiles")),
                    RequestPath = "/static-file"
                });
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
            }
        }
    
    }
    
    

    You can use 1 of 2 ways, go to

    https://localhost:5001/ExportExcel/Export
    

    or

    https://localhost:5001/static-file/employee.xlsx
    
    0 讨论(0)
  • 2020-12-31 10:37

    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)
            );
    }
    
    0 讨论(0)
  • 2020-12-31 10:37

    Following is an example of how you can download a file, you can model your scenario of downloading an Excel file after it:

    public IActionResult Index([FromServices] IHostingEnvironment hostingEnvironment)
    {
        var path = Path.Combine(hostingEnvironment.ContentRootPath, "Controllers", "TextFile.txt");
        return File(System.IO.File.OpenRead(path), contentType: "text/plain; charset=utf-8", fileDownloadName: "Readme.txt");
    }
    

    If the file is in the wwwroot folder, you could do something like below instead:

    public IActionResult Index()
    {
        return File(virtualPath: "~/TextFile.txt", contentType: "text/plain; charset=utf-8", fileDownloadName: "Readme.txt");
    }
    
    0 讨论(0)
提交回复
热议问题