为什么我在这里收到“无法访问封闭的流”?

时间:2016-03-23 17:09:29

标签: c# asp.net .net asp.net-mvc itextsharp

堆栈跟踪看起来像

  

[ObjectDisposedException:无法访问已关闭的流。]
  System.IO .__ Error.StreamIsClosed()+53
  System.IO.MemoryStream.Read(Byte []缓冲区,Int32偏移量,Int32计数)   +11411219 System.Web.Mvc.FileStreamResult.WriteFile(HttpResponseBase response)   +81 System.Web.Mvc.FileResult.ExecuteResult(ControllerContext context)+168
  System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext   controllerContext,ActionResult actionResult)+13

后调用

        //Byte[] bytes;
        using ( var ms = new MemoryStream() )
        {
            using ( var doc = new Document() )
            {
                using ( var writer = PdfWriter.GetInstance(doc, ms) )
                {

                    doc.Open();
                    //var example_html = @"<p>This <em>is </em><span class=""headline"" style=""text-decoration: underline;"">some</span> <strong>sample <em> text</em></strong><span style=""color: red;"">!!!</span></p>";
                    var example_html = System.IO.File.ReadAllText(Path.Combine(Server.MapPath("~/EmailTemplates"), "template.html"));
                    var example_css = @".headline{font-size:200%}";
                    using ( var srHtml = new StringReader(example_html) )
                    {
                        iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml);
                    }
                    using ( var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_css)) )
                    {
                        using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_html)))
                        {
                            iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHtml, msCss);
                        }
                    }


                    doc.Close();
                }
            }
            //bytes = ms.ToArray();
            return File(ms, "application/pdf", "Test.pdf");
        }

我已阅读MemoryStream - Cannot access a closed Stream,但情况并非相同,因为我没有使用StreamReader

修改:仍然无法使用

    [OutputCache(NoStore = true, Duration = 0)]
    public ActionResult Run()
    {
        Byte[] bytes;
        var ms = new MemoryStream();
        try
        {
            using (var doc = new Document())
            {
                using (var writer = PdfWriter.GetInstance(doc, ms))
                {
                    writer.CloseStream = false;
                    doc.Open();
                    var example_html = @"<p>This <em>is </em><span class=""headline"" style=""text-decoration: underline;"">some</span> <strong>sample <em> text</em></strong><span style=""color: red;"">!!!</span></p>";
                    //var example_html = System.IO.File.ReadAllText(Path.Combine(Server.MapPath("~/EmailTemplates"), "LinkEmailTemplate.html"));
                    var example_css = @".headline{font-size:200%}";
                    using (var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_css)))
                    {
                        using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_html)))
                        {
                            iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHtml, msCss);
                        }
                    }
                    doc.Close();
                }
            }
            bytes = ms.ToArray();
            ms.Position = 0;
            return File(ms, "application/pdf", "Test.pdf");
        }
        catch
        {
            ms.Dispose();
            throw;
        }           
    }

2 个答案:

答案 0 :(得分:12)

当您退出操作方法,或者更确切地说,using ( var ms = new MemoryStream() ) {块时,流已关闭。

您无需处置MemoryStream。 File(ms, "application/pdf", "Test.pdf");返回的FileStreamResult对象将dispose it after rendering。实际发送流数据的代码是:

protected async override Task WriteFileAsync(HttpResponse response)
{
    var outputStream = response.Body;

    using (FileStream)
    {
        var bufferingFeature = response.HttpContext.Features.Get<IHttpBufferingFeature>();
        bufferingFeature?.DisableResponseBuffering();

        await FileStream.CopyToAsync(outputStream, BufferSize);
    }
}

您可以使用以下块替换它:

var ms = new MemoryStream();
try
{
     //..
     //From Igor's comment. FileStreamResult won't reset the stream position itself
     ms.Position=0;
     return File(ms, "application/pdf", "Test.pdf");
}
catch
{
    ms.Dispose();
    throw;
}

确保在发生错误时处理流。

<强>更新

正如Igor所说,并且正如源代码所示,FileStreamResult不会重置流位置。在调用return File(...)

之前,您必须将其设置为0

答案 1 :(得分:0)

PdfWriter类可能正在关闭您的信息流。确保将CloseStream属性设置为false。

接下来,您应该 using使用MemoryStream,因为FileStreamResult操作结果将在发送后处理流。现在,在发送之前,流实际上已关闭(通过dispose)。

此外,您应该在发送文件之前将流回寻到位置0。

您可以将整个部分包装在try...catch中,但是如果出现错误则处理该流(但GC最终会处理它并且MemoryStream如果被管理,那么这不是强制性的)。