I'm trying to create a CSV file (using the popular CsvHelper library) in memory and attach it to an email. See the following code:
public async Task<IActionResult> Send() {
using var memoryStream = new MemoryStream();
await CreateAsync(memoryStream, new List<Foo>() {
new Foo()
});
await SendAsync(message => {
message.Attachments.Add(new Attachment(memoryStream), "file.csv", "text/csv");
});
return Content("Sent!");
}
private async Task CreateAsync<T>(Stream stream, IEnumerable<T> records) {
using var writer = new StreamWriter(stream);
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
await csv.WriteRecordsAsync(records);
}
private async Task SendAsync(Action<MailMessage>? options = null) {
using var client = new SmtpClient("xxx", 25);
using var mailMessage = new MailMessage("from@somewhere.com", "to@somewhere.com");
options?.Invoke(mailMessage);
await client.SendMailAsync(mailMessage);
}
This throws the error:
NotSupportedException: Stream does not support reading.
However if I try the following code to attach the file instead, then it works fine:
message.Attachments.Add(new Attachment(new MemoryStream(memoryStream.ToArray()), "file.csv", "text/csv"));
I'd appreciate if someone could help explain why the first example did not work, and how I can update it so that I don't have to create two MemoryStreams.
You are disposing the StreamWriter
and this disposes the underlying stream, from the docs - The StreamWriter object calls Dispose() on the provided Stream object when StreamWriter.Dispose is called.
You can stop this from happening by using the leaveOpen
option.
using var writer = new StreamWriter(stream, leaveOpen: true);