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?
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.
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"));
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With