2012-06-21 28 views
17

Tenía la impresión de que cuando llamaba al Flush() en un objeto StreamWriter, escribe en la transmisión subyacente, pero aparentemente este no es el caso con mi código.StreamWriter escribiendo en MemoryStream

En lugar de escribir en mi archivo, simplemente no escribirá nada. ¿Alguna idea de dónde me estoy equivocando?

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

considera poner tu MemoryStream y StreamWriter en el uso de las declaraciones para la recolección de basura adecuado. – neontapir

+0

@neontapir Todavía no estoy listo para la limpieza del código pero lo haré después. Cheers – ediblecode

+0

@neontapir, comentario incorrecto para este caso en particular: esto solo hará que el problema sea más grave/obvio ... –

Respuesta

24

Creo que necesita establecer Stream.Position = 0. Cuando escribe, avanza la posición hasta el final de la secuencia. Cuando lo pasa al File(), comienza desde la posición en la que está al final.

creo que el siguiente trabajo (no tratar de compilar este):

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

Y de esta manera no va a crear nuevos objetos o copiar la matriz subyacente.

+2

Tenga en cuenta que * no debe * disponer de escritor y transmitir en el código del controlador. Cuando está copiado, es posible que deba agregar un comentario a su código al respecto. –

7

Su MemoryStream se encuentra al final. Un mejor código sería crear una nueva secuencia de memoria R/o en el mismo buffer utilizando el constructor MemoryStream(Byte[], Int32, Int32, Boolean).

más simple r/w en la memoria intermedia recortado:

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

I/O sin copiar el buffer interno:

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

Nota: tenga cuidado de no disponer de la corriente va a devolver a través de Archivo (Corriente). De lo contrario, obtendrás "ObjectDisposedException" de algún tipo. Es decir. si simplemente establece la posición de la transmisión original en 0 y ajusta StreamWriter en el uso, obtendrá la devolución de la transmisión eliminada.

+0

Ordenado así fuera. Gracias – ediblecode

+0

También he añadido precaución al usar 'using' con mi edición. –

+0

Interesante. Como muestro a continuación, pude obtener algo similar para trabajar con la declaración de uso. – neontapir

2

En jugar con esto, tiene el siguiente prototipo para trabajar:

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