J'avais l'impression que lorsque vous appeliez Flush()
dans un objet StreamWriter, il écrit dans le flux sous-jacent, mais apparemment ce n'est pas le cas avec mon code.
Au lieu d'écrire dans mon fichier, il n'écrira rien. Des idées où je me trompe?
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");
}
Je pense que vous devez définir Stream.Position = 0
. Lorsque vous écrivez, il avance la position jusqu'à la fin du flux. Lorsque vous le passez à File()
, il commence à la position où il se trouve - la fin.
Je pense que ce qui suit fonctionnera (n'a pas essayé de le compiler):
stream.Position = 0;
return File(stream, "text/plain", "CompetitionEntries.csv");
Et de cette façon, vous ne créez pas de nouveaux objets ou ne copiez pas le tableau sous-jacent.
Votre MemoryStream est positionné à la fin. Un meilleur code serait de créer un nouveau flux de mémoire R/O sur le même tampon en utilisant MemoryStream (Byte [], Int32, Int32, Boolean) constructeur.
R/W le plus simple sur le tampon découpé:
return File(new MemoryStream(stream.ToArray());
R/o sans copier le tampon interne:
return File(new MemoryStream(stream.GetBuffer(), 0, (int)stream.Length, false);
Remarque: veillez à ne pas supprimer le flux que vous renvoyez via File (Stream). Sinon, vous obtiendrez "ObjectDisposedException" en quelque sorte. C'est à dire. si vous définissez simplement la position du flux d'origine sur 0 et envelopper StreamWriter dans l'utilisation, vous pourrez retourner le flux supprimé.
En jouant avec cela, j'ai fait fonctionner le prototype suivant:
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;
}
}