web-dev-qa-db-fra.com

StreamWriter écrit dans MemoryStream

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");
    }
22
ediblecode

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.

27
David Thielen

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é.

8
Alexei Levenkov

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;
}
}
2
neontapir