Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ASP.NET MVC Controller FileStreamResult error on closed stream?

I am trying to return a csv file from an MVC Controller derived from a List. I came up with the following code for controller based on combining what I read from docs and SO questions. I must be missing something because I am getting yellow screen of death with "Cannot access a closed stream"...

public class ConsumersFileController : Controller
{
    private readonly TDCContext _db = new TDCContext();


    public ActionResult Index()
    {
        IEnumerable<Consumer> list = _db.Consumers.ToList();

        //put List in memory stream object
        MemoryStream memoryStream = new MemoryStream();
        using (memoryStream)
        {
            //return memory stream as file stream result:
            using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, System.Text.Encoding.UTF8, true))
            {
                foreach (var item in list)
                {
                    var itemBytes = item.Serialize();
                    binaryWriter.Write(itemBytes.Length);
                    binaryWriter.Write(itemBytes);

                }

                FileStreamResult fileStream =
                    new FileStreamResult(memoryStream, "application/txt") {FileDownloadName = "zips.csv"};

                return fileStream;
            }
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _db.Dispose();
        }
        base.Dispose(disposing);
    }

}

Here is the stack trace:

[ObjectDisposedException: Cannot access a closed Stream.]
   System.IO.__Error.StreamIsClosed() +59
   System.IO.MemoryStream.Read(Byte[] buffer, Int32 offset, Int32 count) +14731549
   System.Web.Mvc.FileStreamResult.WriteFile(HttpResponseBase response) +93
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +88
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult) +831
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +81
   System.Web.Mvc.Async.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult) +185
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +38
   System.Web.Mvc.Controller.<BeginExecuteCore>b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +67
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +52
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +36
   System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +38
   System.Web.Mvc.MvcHandler.<BeginProcessRequest>b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +43
   System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +67
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +38
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +607
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +134

How can the stream get closed if I am returning the result inside the using block of the stream?

like image 347
Emo333 Avatar asked Aug 19 '17 21:08

Emo333


People also ask

Does FileStreamResult dispose stream?

ASP.NET will handle getting rid of this stream for you once the transfer is complete (part of the FileStreamResult), so you don't need to worry about cleaning it up.

What is FileStreamResult?

FileStreamResult Sends binary content to the response by using a Stream instance when we want to return the file as a FileStream. public FileStreamResult CreateFile() { var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World"));

What is a controller file?

A controller contains the flow control logic for an ASP.NET MVC application. A controller determines what response to send back to a user when a user makes a browser request. A controller is just a class (for example, a Visual Basic or C# class).


1 Answers

You should remove:

using (memoryStream)

FileStreamResult will dispose memoryStream for you.

The reason that your code doesn't work is that the actual work that reads from memoryStream is not in your code - it is in MVC code that calls fileStream.WriteFile. But that code is executed somewhere higher up the call stack. And by the time WriteFile is called (which needs memoryStream) you have already disposed it.

like image 68
mjwills Avatar answered Oct 11 '22 15:10

mjwills