为什么ASP.NET MVC控制器的FileStreamResult会出现“closed stream”错误?

6

我正在尝试从继承自List的MVC控制器返回一个csv文件。 我根据所读文档和SO问题的结合编写了以下控制器代码。 但由于出现“无法访问已关闭的流”的黄色屏幕,我肯定漏掉了什么...

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);
    }

}

以下是堆栈跟踪:

[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

如果我在流的using块中返回结果,流怎么会被关闭呢?

在下一次读取之前,请倒回流。就像 memoryStream.Seek(0, SeekOrigin.Begin)memoryStream.Position=0 - Marko Stanojevic
你能否请澄清一下你到底不理解什么?可能阅读一下using的工作原理实际上可以回答为什么流被关闭...显然@Marko的建议并不能解决这个问题... - Alexei Levenkov
为了澄清我不理解的问题,memoryStream 在 using 块内使用(根据我所读和经历的理解,这意味着一旦 using 块完成,它将被关闭和处理)。fileStream(可能应该将其命名为 fileStreamResult)在 memoryStream using 块内返回。那么,什么时候会关闭 memoryStream? - Emo333
1个回答

11

您应该删除:

using (memoryStream)

FileStreamResult 会为你 自动处理内存流的释放

你的代码无法正常工作的原因是,从 memoryStream 中读取数据的实际工作不在你的代码中 - 而是在调用 fileStream.WriteFile 的 MVC 代码中。但是那段代码在调用栈的更高层次执行。当调用需要 memoryStreamWriteFile 方法时,你已经将它释放了。


1
去掉 using 块,BOOM!就这样了!非常感谢! - Emo333

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接