当前位置: 首页 > news >正文

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/


http://www.taodudu.cc/news/show-911436.html

相关文章:

  • java final关键字
  • 2024制造行业面临的数字挑战
  • 使用 Python 和机器学习预测股票涨跌幅
  • 在线音乐系统
  • 分享四种免费获取SSL的方式
  • React 学习-6-列表 keys
  • .NET Core + Kubernetes:快速体验
  • 海底捞涨价,有错吗?
  • .NET Core + Kubernetes:Pod
  • .NET项目升级手记:可为空引用
  • .NET与鲲鹏共展翅,昇腾九万里(一)
  • 十问十答 Ms-PL 许可证
  • 从案例角度解析建模平台动态规则引擎
  • 想基于K8s按需扩展应用程序,可从这几方面入手
  • EntityFramework Core 3.x上下文构造函数可以注入实例呢?
  • IO 模型知多少
  • 让 .NET 轻松构建中间件模式代码
  • 从编码层面对比java和c#
  • 红帽借“订阅”模式成开源一哥,首创者升任总裁
  • C#两大知名Redis客户端连接哨兵集群的姿势
  • dotNET Core 3.X 请求处理管道和中间件的理解
  • 了解.NET中的垃圾回收
  • 数字化演化历史
  • 如何查找,修复和避免C#.NET中内存泄漏的8个最佳实践
  • ASP.NET Core技术研究-探秘依赖注入框架
  • 从项目到产品: 软件时代需要价值流架构师 | IDCF
  • 推荐一个集录屏、截图、音频于一体的软件给大家
  • WebAssembly增加Go语言绑定
  • .NET中的内存管理
  • .Net微服务实战之技术架构分层篇
  • .NET 下基于动态代理的 AOP 框架实现揭秘
  • Blazor WebAssembly 3.2.0 Preview 4 如期发布
  • C#/.Net Core/WPF框架初建(国际化、主题色)
  • ASP.NET Core 日志框架:Serilog
  • 树莓派销量突然猛增
  • C#黔驴技巧之实现统计结果排名