无法访问 ASP.NET MVC 应用程序中的 Response.OutputStream,因为它已关闭

Posted

技术标签:

【中文标题】无法访问 ASP.NET MVC 应用程序中的 Response.OutputStream,因为它已关闭【英文标题】:Cannot access Response.OutputStream in an ASP.NET MVC application because it's closed 【发布时间】:2018-09-05 10:51:21 【问题描述】:

我正在尝试在我的 Web 应用程序中从另一个域传输文件,我将压缩此文件以供下载。为此,我使用 Ionic Zip。但是我的代码中的标记行出现了这个错误:

System.ObjectDisposedException: 无法访问已关闭的 Stream。

这是我的代码。我在 ASP.NET MVC 应用程序中使用 C#。

using Ionic.Zip;
using System.IO;
using System.Net;

[HttpPost]
public async Task<ActionResult> Downloads(string lang, string product, IEnumerable<string> file, string action)

    string zipname = "manuals.zip";

    using (ZipFile zip = new ZipFile())
    
        foreach (string f in file.Distinct())
        
            using (WebClient client = new WebClient())
            
                using (MemoryStream output = new MemoryStream())
                
                    byte[] b = client.DownloadData(f);
                    await output.WriteAsync(b, 0, b.Length);
                    await output.FlushAsync();
                    output.Position = 0;
                    zip.AddEntry(f.Split('/').Last(), output);
                    output.Close();
                
            
        

        Response.Clear();
        Response.ContentType = "application/zip, application/octet-stream";
        Response.AddHeader("content-disposition", $"attachment; filename=product.Replace('/', '-')-zipname");
        zip.Save(Response.OutputStream); // ← error on this line
        Response.End();
    

这段代码有什么问题?

【问题讨论】:

你能测试一下如果你不释放内存流并且不调用 close 会发生什么。可能会延迟读取实际内存流,直到调用Save。在您的代码中,所有这些流都已经关闭、处置,甚至可能被 GC。 @rene:这行得通。但是所有的流会在Response.End() 之后关闭还是我必须手动关闭? 调用者通常负责关闭/处理它创建的内容。它可能会转移这种责任,但它必须明确地这样做。这些都不适用于 HttpResponse 的能力,所以是的,您需要手动完成。 【参考方案1】:

通过@rene 的评论,我找到了一个可行的答案。他说:

如果您不处置 MemoryStream 并且不调用 close 它,您能测试一下会发生什么。可能会延迟读取实际内存流,直到调用 Save 为止。在您的代码中,所有这些流都已经关闭、处置,甚至可能被 GC。

在这里查看我的代码。

using Ionic.Zip;
using System.IO;
using System.Net;

[HttpPost]
public ActionResult Downloads(string lang, string product, IEnumerable<string> file, string action)

    string zipname = "manuals.zip";
    List<MemoryStream> streams = new List<MemoryStream>();

    using (ZipFile zip = new ZipFile())
    
        foreach (string f in file.Distinct())
        
            using (WebClient client = new WebClient())
            
                MemoryStream output = new MemoryStream();
                byte[] b = client.DownloadData(f);

                output.Write(b, 0, b.Length);
                output.Flush();
                output.Position = 0;
                zip.AddEntry(f.Split('/').Last(), output);

                // output.Close(); // ← removed this line
                streams.Add(output);
            
        

        Response.Clear();
        Response.ContentType = "application/zip, application/octet-stream";
        Response.AddHeader("content-disposition", $"attachment; filename=product.Replace('/', '-')-zipname");
        zip.Save(Response.OutputStream);

        foreach (MemoryStream stream in streams)
        
            stream.Close();
            stream.Dispose();
        

        Response.End();
    

为了确保所有流都已关闭,我已将所有打开的 MemoryStreams 添加到列表中,在 Response.End(); 之前,我关闭并将它们全部处理掉。

【讨论】:

以上是关于无法访问 ASP.NET MVC 应用程序中的 Response.OutputStream,因为它已关闭的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core mvc 应用程序中的 FFMPEG 录制

从 ASP.Net MVC 视图访问应用程序设置

无法从 Asp.Net Mvc 应用程序中找到 DataContractJsonSerializer

如何在 ASP.NET MVC 5 中访问 AspNetUserRoles 表

在 Apache 上运行 ASP.net MVC 时无法访问 elmah.axd

ASP.Net 核心 MVC 中的本地化不起作用 - 无法找到资源文件