Question

I have a Controller which returns a FileStreamResult via SharpZipLib (I have tried DotNetZip and there is no difference).

using (var buffer = new MemoryStream())
{
    using (var zipStream = new ZipOutputStream(buffer))
    {
        zipStream.PutNextEntry(new ZipEntry("The Simpsons"));
        var bart = Encoding.UTF8.GetBytes("Homer <3 donuts");
        zipStream.Write(bart, 0, bart.Length);
        zipStream.IsStreamOwner = false;    
        return File(buffer, MediaTypeNames.Application.Zip, fileName);
    }
}

I am trying to unit test this as such:

var controller = new SimpsonsController();
var result = controller.ConfigurationReport(id);
Assert.IsInstanceOf<FileStreamResult>(result);

var streamResult = (FileStreamResult) result;
var zipInputStream = new ZipInputStream(streamResult.FileStream);

Assert.IsNotNull(zipInputStream);

var zipEntry = zipInputStream.GetNextEntry();
Assert.AreEqual("The Simpsons", zipEntry.Name);

Now the unit test fails with:

System.ObjectDisposedException : Cannot access a closed Stream.
   at System.IO.__Error.StreamIsClosed()
   at System.IO.MemoryStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer.Fill()
   at ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer.ReadLeByte()
   at ICSharpCode.SharpZipLib.Zip.Compression.Streams.InflaterInputBuffer.ReadLeInt()
   at ICSharpCode.SharpZipLib.Zip.ZipInputStream.GetNextEntry()

If I try to directly download via a browser, IIS 500s with a similar stacktrace:

Cannot access a closed Stream.
System.ObjectDisposedException: Cannot access a closed Stream.
   at System.IO.MemoryStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.Web.Mvc.FileStreamResult.WriteFile(HttpResponseBase response)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)

Has anyone tested this kind of stream-based file returning controllers? How did you succeed? Should I simply NOT dispose my classes? Really?

Was it helpful?

Solution

Try this, I think your problem is you are disposing of the stream that is being returned.

public FileStreamResult PDF()
{
    MemoryStream buffer = new MemoryStream();
    using (var zipStream = new ZipOutputStream(buffer))
    {
        zipStream.PutNextEntry(new ZipEntry("The Simpsons"));
        var bart = Encoding.UTF8.GetBytes("Homer <3 donuts");
        zipStream.Write(bart, 0, bart.Length);
        zipStream.IsStreamOwner = false;
    }
    return File(buffer, MediaTypeNames.Application.Zip, fileName);
}

Take a look at this https://stackoverflow.com/a/10891136/985284 and follow other posts from Cheeso for more info.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top