2012-06-21 18 views
17

Ho avuto l'impressione che quando hai chiamato Flush() in un oggetto StreamWriter, esso scrive nello stream sottostante, ma apparentemente questo non è il caso del mio codice.StreamWriter scrittura su MemoryStream

Invece di scrivere sul mio file non scriverà nulla. Qualche idea su dove sto andando male?

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"); 
    } 
+2

considerare di mettere il vostro MemoryStream e StreamWriter nell'utilizzo dichiarazioni per una corretta raccolta dei rifiuti. – neontapir

+0

@neontapir Non sono ancora in giro per la pulizia del codice ma lo farò dopo. Cheers – ediblecode

+0

@neontapir, commento sbagliato per questo caso particolare: questo renderà solo il problema più grave/ovvio ... –

risposta

24

Credo che sia necessario impostare Stream.Position = 0. Quando scrivi, avanza fino alla fine del flusso. Quando lo passi a File() inizia dalla posizione in cui si trova - alla fine.

Penso che la seguente funziona (non provate a compilare questo):

stream.Position = 0; 
return File(stream, "text/plain", "CompetitionEntries.csv"); 

E in questo modo non si sta creando nuovi oggetti o la copia della matrice sottostante.

+2

Si prega di notare che * non è necessario * disporre di writer e streaming nel codice del controller. Quando hai copiato la copia potresti dover aggiungere commenti al tuo codice. –

7

Il tuo MemoryStream è posizionato alla fine. Un codice migliore sarebbe quello di creare un nuovo flusso di memoria R/o sullo stesso buffer usando il costruttore MemoryStream(Byte[], Int32, Int32, Boolean).

più semplice r/w sul buffer rifilato:

return File(new MemoryStream(stream.ToArray()); 

R/O senza copiare il buffer interno:

return File(new MemoryStream(stream.GetBuffer(), 0, (int)stream.Length, false); 

Nota: fare attenzione a non smaltire il flusso si restituisce tramite File (stream). Altrimenti riceverai "ObjectDisposedException" di qualche tipo. Cioè se si imposta semplicemente la posizione del flusso originale su 0 e si esegue il wrapping di StreamWriter, verrà restituito lo stream disposto.

+0

Ordinato bene. Grazie – ediblecode

+0

Ho anche aggiunto cautela nell'usare "usare" con la mia modifica. –

+0

Interessante. Come mostro di seguito, sono riuscito a ottenere qualcosa di simile a lavorare con l'istruzione using. – neontapir

2

In giocare con questo, ho avuto il seguente prototipo al lavoro:

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