ASP.NET Core:内存生成CSV邮件附件报错及无二次流优化问询
报错原因分析
你遇到的NotSupportedException: Stream does not support reading,核心原因是StreamWriter默认会在Dispose时关闭底层流:
- 当用
using语句包裹StreamWriter或CsvWriter时,Dispose操作会自动关闭底层的MemoryStream,此时流的CanRead属性变为false,邮件附件组件尝试读取已关闭的流时就会抛出该异常。 - 另一个次要问题(虽不会直接引发此异常,但会导致空附件):写完CSV后,流的
Position停在数据末尾,若不重置,读取操作会从末尾开始,无法获取有效内容。
你通过复制内存流数组新建MemoryStream能正常运行,是因为复制操作是在原流还未被关闭时完成的,新建的流是独立的可读写流,不受原流状态影响,但这种方式会额外复制一份数据,占用更多内存。
无需双MemoryStream的优化方案
关键是让StreamWriter在Dispose时不关闭底层流,同时重置流的读取位置到开头,直接使用原流作为附件:
using System.Globalization; using System.IO; using System.Net.Mail; using CsvHelper; // 1. 创建内存流 var csvStream = new MemoryStream(); // 2. 创建StreamWriter时指定leaveOpen: true,避免Dispose时关闭底层流 using var streamWriter = new StreamWriter(csvStream, leaveOpen: true); using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture); // 3. 写入CSV数据 csvWriter.WriteRecords(yourDataCollection); // 替换为你的实际数据集合 // 4. 刷新缓冲区,确保所有数据写入流 streamWriter.Flush(); // 5. 将流的位置重置到起始处,让附件读取时能获取完整数据 csvStream.Position = 0; // 6. 直接将原流作为邮件附件添加 var mailAttachment = new Attachment(csvStream, "data.csv", "text/csv"); mailMessage.Attachments.Add(mailAttachment); // 注意:MailMessage在Dispose时会自动处理附件的流,无需手动关闭csvStream
要点说明
leaveOpen: true:这是核心设置,告诉StreamWriter在自身被Dispose时不要关闭底层的MemoryStream,保留流的可读写状态。Flush():确保StreamWriter缓冲区中的所有数据都写入到MemoryStream中,避免数据丢失。Position = 0:将流的读取指针重置到开头,保证邮件附件能读取到完整的CSV内容。
内容的提问来源于stack exchange,提问作者nfplee
相关产品推荐
相关产品推荐

