web-dev-qa-db-fra.com

Pourquoi ai-je le message "Impossible d'accéder à un flux fermé" ici?

Trace de pile ressemble à 

[ObjectDisposedException: impossible d'accéder à un flux fermé.]
System.IO .__ Error.StreamIsClosed () +53
System.IO.MemoryStream.Read (tampon Byte [], décalage Int32, compte Int32) +11411219 System.Web.Mvc.FileStreamResult.WriteFile (réponse HttpResponseBase) +81 System.Web.Mvc.FileResult.ExecuteResult (contexte ControllerContext) +168
System.Web.Mvc.ControllerActionInvoker.InvokeActionResult (ControllerContext ControllerContext, ActionResult actionResult) +13

après avoir invoqué 

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

J'ai lu MemoryStream - Impossible d'accéder à un flux fermé , mais ce n'est pas le même scénario car je n'utilise pas StreamReader

Edit: Ne fonctionne toujours pas avec 

    [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;
        }           
    }
6
Subpar Web Dev

Le flux a été fermé dès que vous avez quitté la méthode d'action ou plutôt le bloc using ( var ms = new MemoryStream() ) {.

Vous n'avez pas besoin de jeter le MemoryStream. L'objet FileStreamResult renvoyé par File(ms, "application/pdf", "Test.pdf"); sera le disposera après le rendu . Le code qui envoie les données du flux est le suivant:

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

Vous pouvez remplacer ce bloc en utilisant:

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

pour s'assurer que le flux est éliminé en cas d'erreur.

METTRE &AGRAVE; JOUR

Comme Igor l'a mentionné, et comme le code source l'indique, FileStreamResult ne réinitialise pas la position du flux. Vous devrez le mettre à 0 avant d'appeler return File(...)

11
Panagiotis Kanavos

La classe PdfWriter ferme peut-être votre flux. Assurez-vous de définir la propriété CloseStream sur false.

Ensuite, vous devriez non utiliser using sur la MemoryStream ici, car le résultat de l'action FileStreamResult permettra de supprimer le flux après l'avoir envoyé. Actuellement, le flux est effectivement fermé (par disposition) avant que l’envoi ait lieu.

Vous devez également rechercher le flux en position 0 avant d’envoyer le fichier.

Vous pouvez toutefois insérer la totalité de la pièce dans un try...catch afin d'éliminer le flux en cas d'erreur (mais le GC s'en occupera éventuellement et MemoryStream s'il est géré, ce n'est donc pas obligatoire).

0
Lucero