Запись StreamWriter в MemoryStream
У меня создалось впечатление, что при вызове Flush()
в объекте StreamWriter он записывает в основной поток, но, видимо, это не так с моим кодом.
Вместо того, чтобы писать в мой файл, он ничего не напишет. Любые идеи, в которых я ошибаюсь?
public FileResult DownloadEntries(int id)
{
Competition competition = dataService.GetCompetition(id);
IQueryable<CompetitionEntry> entries = dataService.GetAllCompetitionEntries().Where(e => e.CompetitionId == competition.CompetitionId);
MemoryStream stream = new MemoryStream();
StreamWriter csvWriter = new StreamWriter(stream, Encoding.UTF8);
csvWriter.WriteLine("First name,Second name,E-mail address,Preferred contact number,UserId\r\n");
foreach (CompetitionEntry entry in entries)
{
csvWriter.WriteLine(String.Format("{0},{1},{2},{3},{4}",
entry.User.FirstName,
entry.User.LastName,
entry.User.Email,
entry.User.PreferredContactNumber,
entry.User.Id));
}
csvWriter.Flush();
return File(stream, "text/plain", "CompetitionEntries.csv");
}
Ответы
Ответ 1
Думаю, вам нужно установить Stream.Position = 0
. Когда вы пишете, он продвигает позицию до конца потока. Когда вы передаете его в File()
, он начинается с позиции, в которой он находится, - конца.
Я думаю, что следующее будет работать (не пытайтесь скомпилировать это):
stream.Position = 0;
return File(stream, "text/plain", "CompetitionEntries.csv");
И таким образом вы не создаете никаких новых объектов или не копируете базовый массив.
Ответ 2
Ваш MemoryStream позиционируется в конце. Лучше всего было бы создать новый поток памяти R/o в том же буфере, используя MemoryStream (Byte [], Int32, Int32, Boolean) constructor.
Простейший r/w на обрезаемом буфере:
return File(new MemoryStream(stream.ToArray());
R/o без копирования внутреннего буфера:
return File(new MemoryStream(stream.GetBuffer(), 0, (int)stream.Length, false);
Примечание. Будьте осторожны, чтобы не передавать поток, который вы возвращаете через File (Stream). В противном случае вы получите "ObjectDisposedException". То есть если вы просто установите положение исходного потока на 0 и оберните StreamWriter в использование, вы получите возвращаемый удаленный поток.
Ответ 3
Играя с этим, я получил следующий прототип для работы:
using System.Web.Mvc;
using NUnit.Framework;
namespace StackOverflowSandbox
{
[TestFixture]
public class FileStreamResultTest
{
public FileStreamResult DownloadEntries(int id)
{
// fake data
var entries = new[] {new CompetitionEntry { User = new Competitor { FirstName = "Joe", LastName = "Smith", Email = "[email protected]", Id=id.ToString(), PreferredContactNumber = "555-1212"}}};
using (var stream = new MemoryStream())
{
using (var csvWriter = new StreamWriter(stream, Encoding.UTF8))
{
csvWriter.WriteLine("First name,Second name,E-mail address,Preferred contact number,UserId\r\n");
foreach (CompetitionEntry entry in entries)
{
csvWriter.WriteLine(String.Format("{0},{1},{2},{3},{4}",
entry.User.FirstName,
entry.User.LastName,
entry.User.Email,
entry.User.PreferredContactNumber,
entry.User.Id));
}
csvWriter.Flush();
}
return new FileStreamResult(new MemoryStream(stream.ToArray()), "text/plain");
}
}
[Test]
public void CanRenderTest()
{
var fileStreamResult = DownloadEntries(1);
string results;
using (var stream = new StreamReader(fileStreamResult.FileStream))
{
results = stream.ReadToEnd();
}
Assert.IsNotEmpty(results);
}
}
public class CompetitionEntry
{
public Competitor User { get; set; }
}
public class Competitor
{
public string FirstName;
public string LastName;
public string Email;
public string PreferredContactNumber;
public string Id;
}
}