7

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?

3
  • Rewind stream before next reading. Like memoryStream.Seek(0, SeekOrigin.Begin) or memoryStream.Position=0 Commented Aug 19, 2017 at 22:00
  • Can you please clarify what exactly you don't understand? Possibly reading on how using work may actually answer why stream get closed... Obviously @Marko's suggestion not going to solve that... Commented Aug 19, 2017 at 22:51
  • To clarify what I don't understand, the memoryStream is being used inside a using block (which from my understanding from what I have read and experienced, means it will be closed and disposed of once the using block is done). The fileStream (probably should have named it fileStreamResult) is returned INSIDE the memoryStream using block. So, at what point is the memoryStream being closed? Commented Aug 19, 2017 at 23:27

1 Answer 1

12

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Removed the using block and BOOM! That was it! thank you so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.