web-dev-qa-db-ja.com

ここで「閉じたストリームにアクセスできません」と表示されるのはなぜですか?

スタックトレースは次のようになります

[ObjectDisposedException:閉じたストリームにアクセスできません。]
System.IO .__ Error.StreamIsClosed()+53
System.IO.MemoryStream.Read(Byte [] buffer、Int32 offset、Int32 count)+11411219 System.Web.Mvc.FileStreamResult.WriteFile(HttpResponseBase response)+81 System.Web.Mvc.FileResult.ExecuteResult (ControllerContextコンテキスト)+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-閉じたストリームにアクセスできません ですが、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;
        }           
    }
8
Subpar Web Dev

アクションメソッドまたはusing ( var ms = new MemoryStream() ) {ブロックを終了するとすぐにストリームが閉じられました。

MemoryStreamを破棄する必要はありません。 File(ms, "application/pdf", "Test.pdf");によって返されるFileStreamResultオブジェクトは レンダリング後に破棄 します。実際にストリームデータを送信するコードは次のとおりです。

_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に設定する必要があります

12

PdfWriterクラスがストリームを閉じている可能性があります。 CloseStream プロパティを必ずfalseに設定してください。

次に、usingアクションの結果は次のようになるので、ここでMemoryStreamに対してFileStreamResultしないでください送信後のストリームの破棄に注意してください。現在、ストリームは送信が行われる前に(破棄によって)実際に閉じられています。

また、ファイルを送信する前に、ストリームを位置0に戻す必要があります。

全体をtry...catchただし、エラーが発生した場合にストリームを破棄します(ただし、最終的にはGCが処理し、適切に管理されている場合はMemoryStreamになるため、必須ではありません)。

0
Lucero