Search code examples
c#asp.netasp.net-mvcstreamnpoi

Corrupt File when streaming from HTTP


I’m having an issue with streaming a file through the HTTP Response. No matter what I do, it comes out corrupted!

The background is that I need to send a generated XLS file (I'm using NPOI). I know that the generated file is fine, because if I save it directly to the disk with a FileStream, I can open it and there are no problems! However… when I try to stream that file through HTTP, it comes out corrupted (I’ve tried three different methods, shown below…). To add on top of that, it’s not only the XLS file that gets corrupted, it’s ALL files that I load (I’ve tried jpg, png, and txt files). Whenever I send them through HTTP, it gets corrupted.Anyways, here’s what I’ve tried:

  1. I’ve tried manually constructing an HTTP response:

    Export export = new Export(header, data); 
    MemoryStream stream = export.GetXLSStream("test"); // This generates a memory stream of the XLS file
    
    // Writing that stream to a file works! This file opens just fine
    var fs = new FileStream(@"C:\export.xls", FileMode.Create, System.IO.FileAccess.Write);
    stream.WriteTo(fs);
    
    // However, this doesn't!
    Response.ClearContent();
    Response.AddHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
    Response.AddHeader("Content-Disposition", "attachment; filename=export.xls");
    Response.AddHeader("Content-Type", "application/vnd.ms-excel");
    Response.AddHeader("Content-Transfer-Encoding", "binary");
    Response.BinaryWrite(stream.ToArray());
    Response.End();
    return null;
    
  2. I’ve tried using the FileStreamResult:

    Export export = new Export(header, data); 
    MemoryStream stream = export.GetXLSStream("test"); // This generates a memory stream of the XLS file
    
    return File(stream, "application/vnd.ms-excel", "export.xsl");
    
  3. I’ve tried using the FileContentResult:

    Export export = new Export(header, data); 
    MemoryStream stream = export.GetXLSStream("test"); // This generates a memory stream of the XLS file
    
    return File(stream.ToArray(), "application/vnd.ms-excel", "export.xsl");
    
  4. I’ve tried using a FilePathResult:

    Export export = new Export(header, data); 
    MemoryStream stream = export.GetXLSStream("test"); // This generates a memory stream of the XLS file
    
    var fs = new FileStream(@"C:\export.xls", FileMode.Create, System.IO.FileAccess.Write);
    stream.WriteTo(fs);
    fs.Close();
    
    return File(@"C:\export.xls", "application/vnd.ms-excel", "export.xsl");
    
  5. And I’ve tried loading random files like:

    return File(@"C:\test.jpg", "image/jpeg", "test.jpg");
    

Doing a MD5 or CRC check also shows me that the file I get through HTTP is not the same as the original file (even though they have the exact same amount of bytes).


Solution

  • Looks like it was a Whitespace filter I had applied at the controller's root to make the output all a single line. It shouldn't have been applied to anything but an html response, but I've changed the code so that it doesn't run at all for response like this.