ASP.NET CORE WEBAPI文件下载

最近要使用ASP.NET CORE WEBAPI用来下载文件,使用的.NET CORE 3.1。考虑如下场景:

  1. 文件是程序生成的。
  2. 文件应该能兼容各种格式。
  3. 浏览器可以感知进行下载。

准备

经过简单的调研,得到以下结论。

  • ASP.NET CORE 提供FileResult这种类型的ActionResult,可以直接返回文件结果,不需要直接处理HttpResponse。
  • 通过Stream可以直接返回文件流供浏览器下载。
  • FileStreamResult是FileResult的具体实现,返回值应该是此类对象。
  • Stream有多种类型,适合直接内存中生成文件对象的是MemoryStream。

    对目标有了基础的了解,就可以开始动手实现了。

实现

建立好ASP.NET CORE WEBAPI工程,把生成文件的代码独立出来一个函数。我这里需要是下载一个CSV格式的文件,因此生成一个CSV文件。

对于磁盘上的文件,可以使用FileStream对象,由于我这里需要运行中生成这个文件,需要使用MemoryStream。

using var stream = new MemoryStream();
using var writer = new StreamWriter(stream);
//生成标题
var propCollection = ttype.GetProperties();
foreach (var n in propCollection)
{
    writer.Write(n.Name);
    writer.Write(",");
}
writer.WriteLine();
//生成内容
foreach (var item in res)
{
    foreach (var n in propCollection)
    {
        writer.Write(Convert.ToString(n.GetValue(item)));
        writer.Write(",");
    }
    writer.WriteLine();
}
  1. 请不要考虑里面反射的相关内容,按照自己的逻辑生成CSV即可,我只是懒得改代码而已。
  2. 代码中使用到了一些新的语法特性,请注意对低版本的.NET不一定适用。

    直接返回Stream对象给Controller处理,处理代码如下:

var res = await info.GetAllQueryResult();
var actionresult = new FileStreamResult(res, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("text/csv"));
return actionresult;

CSV的Content-Type是text/csv,如果下载别的文件,请自行查询MIME格式。

调试

直接执行上面的代码,直接报错“无法读取已经关闭的流”。猜测是离开using语句块的时候,stream自动被关闭了。改动很简单,去掉using语句,不再报相同错误。

但是返回的文件长度一直是0,单步调试发现Writer执行完毕之后,stream返回的长度是0,内容实际上并没有写入,想起有一个Flush(),可以添加以确保数据写入。

单步显示stream长度有了,但是返回的长度还是0。继续单步调试发现Stream的Postion是停在文件结尾的,这个和直接开始读取文件完全不一样,文件读取一般是从开头开始的,于是直接设置Postion为0,问题解决。

下载能够成功了,但是文件名一直显示的是随机生成的,体验很差。设置一下FileDownloadName即可。

核心代码如下:

public async Task<Stream> GetAllQueryResult()
{
    var stream = new MemoryStream();
    var writer = new StreamWriter(stream);
    //生成标题
    var propCollection = ttype.GetProperties();
    foreach (var n in propCollection)
    {
        writer.Write(n.Name);
        writer.Write(",");
    }
    writer.WriteLine();
    //生成内容
    foreach (var item in res)
    {
        foreach (var n in propCollection)
        {
            writer.Write(Convert.ToString(n.GetValue(item)));
            writer.Write(",");
        }
        writer.WriteLine();
    }
    writer.Flush();
    stream.Position = 0;
    return stream;
}
[HttpPost("file")]
[ProducesResponseType(typeof(FileResult), Status200OK)]
public async Task<FileResult> Download()
{
    var info = new Info();
    var res = await info.GetAllQueryResult();

    var actionresult = new FileStreamResult(res, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("text/csv"));
    actionresult.FileDownloadName = "Carinfos.csv";
    //Response.ContentLength = res.Length;
    return actionresult;
}

使用swagger调用,最后效果:

总结

后来查了一些资料,总结了一下:

  • MemoryStream如果使用using语句,会在离开代码块的时候自动关闭,实际上ASP.NET CORE会自动处理关闭的事项,不需要使用using语句。
  • 由于生成文件的过程是从文件流的开头一直进行到末尾的,因此向请求端返回结果时,应当重置Stream的游标,从0开始传输。
  • 记得在使用writer之后使用Flush()以确保数据有写入。
  • 如果不确定文件格式,可以直接返回MIME值为application/oct-stream。
  • 设置FileStreamResult的FileDownloadName属性可以修改文件的默认名称。
  • (可选)可以通过设置Response.ContentLength来设置文件的长度。

参考资料:

https://darchuk.net/2019/05/31/asp-net-core-web-api-returning-a-filestream/

原文地址:https://www.cnblogs.com/podolski/p/12682978.html

时间: 2024-10-27 05:36:25

ASP.NET CORE WEBAPI文件下载的相关文章

Asp.net Core WebApi 使用Swagger做帮助文档,并且自定义Swagger的UI

WebApi写好之后,在线帮助文档以及能够在线调试的工具是专业化的表现,而Swagger毫无疑问是做Docs的最佳工具,自动生成每个Controller的接口说明,自动将参数解析成json,并且能够在线调试. 那么要讲Swagger应用到Asp.net Core中需要哪些步骤,填多少坑呢? 安装Swagger到项目 { "dependencies": { "Swashbuckle": "6.0.0-beta902", ........ 或者直接通

Asp.net core WebApi 使用Swagger生成帮助页实例

最近我们团队一直进行.net core的转型,web开发向着前后端分离的技术架构演进,我们后台主要是采用了asp.net core webapi来进行开发,开始每次调试以及与前端人员的沟通上都存在这效率低下的问题,一次在看微软asp.net core官方文档的时候,发现了swagger这个好东西.然后在实际的项目中引入了该技术.我们开发人员测试自己写的api的过程大大得到了简化,前端人员也可以根据我们提供的swagger help pages 自己进行一些前端代码的测试,大大提高了前后端的开发效

Asp.Net Core WebApi学习笔记(四)-- Middleware

Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Middleware功能支持. 在演示Middleware功能之前,先要了解一下Asp.Net管道模型发生了什么样的变化. 第一部分:管道模型 1. Asp.Net管道 在之前的Asp.Net里,主要的管道模型流程如下图所示: 请求进入Asp.Net工作进程后,由进程创建HttpWorkRequest对象

ASP.NET Core WebAPI 开发-新建WebAPI项目 转

转 http://www.cnblogs.com/linezero/p/5497472.html ASP.NET Core WebAPI 开发-新建WebAPI项目 ASP.NET Core WebAPI 开发-新建WebAPI项目, ASP.NET Core 1.0 RC2 即将发布,我们现在来学习一下 ASP.NET Core WebAPI开发. 网上已经有泄露的VS2015 Tooling,需要VS2015 Update 2. .NET Core 1.0.0 RC2 SDK Preview

Asp.net core WebApi 使用Swagger生成帮助页

最近我们团队一直进行.net core的转型,web开发向着前后端分离的技术架构演进,我们后台主要是采用了asp.net core webapi来进行开发,开始每次调试以及与前端人员的沟通上都存在这效率低下的问题,一次在看微软asp.net core官方文档的时候,发现了swagger这个好东西.然后在实际的项目中引入了该技术.我们开发人员测试自己写的api的过程大大得到了简化,前端人员也可以根据我们提供的swagger help pages 自己进行一些前端代码的测试,大大提高了前后端的开发效

Asp.Net Core WebAPI入门整理(三)跨域处理

一.Core  WebAPI中的跨域处理  1.在使用WebAPI项目的时候基本上都会用到跨域处理 2.Core WebAPI的项目中自带了跨域Cors的处理,不需要单独添加程序包 3.使用方法简单 二.使用实例 1.全局配置中启用跨域处理,命名为'any',任何都可以访问 public void ConfigureServices(IServiceCollection services) { //配置跨域处理 services.AddCors(options => { options.AddP

ASP.NET Core WebAPI 开发-新建WebAPI项目

小分享:我有几张阿里云优惠券,用券购买或者升级阿里云相应产品最多可以优惠五折!领券地址:https://promotion.aliyun.com/ntms/act/ambassador/sharetouser.html?userCode=ohmepe03 ASP.NET Core WebAPI 开发-新建WebAPI项目, ASP.NET Core 1.0 RC2 即将发布,我们现在来学习一下 ASP.NET Core WebAPI开发. 网上已经有泄露的VS2015 Tooling,需要VS2

Asp.Net Core WebAPI入门整理(二)简单示例

一.Core WebAPI中的序列化 使用的是Newtonsoft.Json,自定义全局配置处理: // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { //使用IMvcBuilder 配置Json序列化处理 services.AddMvc()

Asp.Net Core WebAPI入门整理(一)

一.Asp.Net Core  WebAPI 1.目前版本是v1.1 2.默认路由处理和Asp.Net WebAPI有些 区别了,现在使用的是控制器路由[Route("api/Menu")]和请求方式路由[HttpGet].[HttpGet("{id}")]结合的 方式.直接在控制器和Action上使用方法注释. 3.从项目结构依赖上看 Asp.Net Core MVC项目其实已经包含了WebAPI 二.使用Visual Studio 2017创建Asp.Net C