如何从ASP.NET Core Web API web应用程序返回Excel文件?

20

在类似的问题中,使用此代码可下载PDF:

我正在测试放置于控制器文件夹内的本地文件(.xlsx、.pdf、.zip)。

这里有一个类似的问题

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

这个很好用!

但是当测试其他文件时,比如Excel文件(.xlsx)或ZIP文件(.zip),测试就不能正常工作了。

代码:

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

结果: 在这里输入图片描述

我还测试了以下Content-Type:

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

得到相同的结果。

哪种方式是返回任何文件类型的正确方法?

感谢您的回答。


1
你需要添加一个 Content-Disposition 头部,类型为 attachment - Kalten
添加HttpContext.Response.Headers.Add("Content-disposition", "attachment"); 但要获得相同的结果。 - Jose Eduardo Poma Caceres
我们将 xls 文件读入一个字节数组中,并将其作为 Base64 编码字符串返回。 - lcryder
将字符集设置为 utf-8? - Tratcher
在Reactjs中下载Excel文件 --> https://dev59.com/wVkT5IYBdhLWcg3wPtIv#73421257 - ABHIJEET KHIRE
5个回答

15

我的(工作)解决方案:

  • 我有一个类,使用EPPlus.Core动态创建XLSX文件。
    • 这会返回生成文件路径的FileInfo

这是我控制器中的内容:

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

这是我在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)
        );
}

1
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 的 contentType 对我起作用了。 - Mike Finch

4

我曾经遇到过同样的问题。我的问题是由于客户端请求引起的,而不是服务器响应引起的。我通过在我的Get请求头选项中添加响应内容类型来解决这个问题。以下是我在Angular 2中的示例。

来自客户端(Angular 2)的请求**需要使用filesaver.js库。

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

服务器端代码。(.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);
    }

以下是相关参考链接,如有需要请查看:

AngularJs应用程序中的下载文件损坏

C#文件下载出现损坏


在Reactjs中下载Excel文件 --> https://dev59.com/wVkT5IYBdhLWcg3wPtIv#73421257 - ABHIJEET KHIRE

1
以下是一个示例,展示如何下载文件。您可以根据此模拟下载Excel文件的场景。
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");
}

如果文件在 wwwroot 文件夹中,您可以像下面这样操作:
public IActionResult Index()
{
    return File(virtualPath: "~/TextFile.txt", contentType: "text/plain; charset=utf-8", fileDownloadName: "Readme.txt");
}

0
// imports
import * as FileSaver from "file-saver";
import axios from "axios";

export default function App() {
   // function to download file
  const downloadExcelFileFun = () => {
    axios
      .post(
        `https://yourapp.test.com/api/v1/myexcelfile/demoExcelfile`,
        {
          // api payload data if any
        },
        {
          headers: {
            Authorization: `Bearer TOKEN_STRING`,
          },
          responseType: "blob",
        }
      )
      .then((res) => {
        // the res.data is of type blob
        FileSaver.saveAs(res.data, "exampleFile.xlsx");
      });
  };

  return (
    <div className="App">
      <button
        onClick={() => {
          downloadExcelFileFun();
        }}
      >
        Download xLsx File
      </button>
    </div>
  );
}

0
你可以使用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;
    }

}

文件 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();
            });
        }
    }

}

你可以使用两种方法之一,前往

https://localhost:5001/ExportExcel/Export

或者

https://localhost:5001/static-file/employee.xlsx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接