【问题标题】:FilestreamResult not openingFilestreamResult 未打开
【发布时间】:2016-04-20 23:43:41
【问题描述】:

我的控制器中有这两种方法。我想打开返回文件流结果的 FilestreamResult pdf()。但是,当使用自定义 TextWriter 时,我得到 OutputStream is not available 错误。我正在使用 itextsharp .pdf 这是我的代码:

  public FileStreamResult pdf()
    {
        MemoryStream workStream = new MemoryStream();
        Document document = new Document();
        PdfWriter.GetInstance(document, workStream).CloseStream = false;
        List<Plant> plants = new List<Plant>();
        foreach (var item in context.Plants)
        {
            plants.Add(item);
        }


        byte[] byteInfo = GeneratePdf(plants);
        workStream.Write(byteInfo, 0, byteInfo.Length);
        workStream.Position = 0;

        return new FileStreamResult(workStream, "application/pdf");
    }

生成pdf的方法是

private static byte[] GeneratePdf(List<Plant> plants)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (var doc = new Document())
            {
                PdfWriter.GetInstance(doc, memoryStream);

                doc.Open();
                doc.SetMargins(120, 120, 270, 270);
                BaseFont font = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false);
                Font normalFont = new Font(font, 12, Font.NORMAL, BaseColor.BLACK);





                Paragraph pgTitle = new Paragraph();
                pgTitle.Font = new Font(font, 20, Font.NORMAL, BaseColor.BLACK); 
                pgTitle.Add("American University of Beirut");
                doc.Add(pgTitle);

                Paragraph pgPlantTitle = new Paragraph();

                pgPlantTitle.Font = new Font(font, 18, Font.NORMAL, BaseColor.BLACK);
                pgPlantTitle.Add("Plant Description");
                doc.Add(pgPlantTitle);

                foreach (Plant p in plants)
                {
                    Paragraph plantDisc = new Paragraph();

                    plantDisc.Font = new Font(font, 14, Font.NORMAL, BaseColor.BLACK);
                    plantDisc.Add(p.ScientificName);

                    plantDisc.Add(p.TypeOfPlants.ToString());                      
                    plantDisc.Add(p.PlantHeightRanges.ToString());
                    plantDisc.Add(p.PlantSpreadRanges.ToString());
                    plantDisc.Add(p.PlantShapes.ToString());
                    plantDisc.Add(p.NativeOrigin);
                    plantDisc.Add(p.Colors.ToString());
                    plantDisc.Add(p.Colors1.ToString());
                    plantDisc.Add(p.LightRequirements.ToString());
                    plantDisc.Add(p.WaterRequirements.ToString());

                    doc.Add(plantDisc);

                    doc.Add(new Paragraph(" "));

                }
                doc.Close();
                memoryStream.Close();
                return memoryStream.ToArray();
            }
        }
    }

有什么帮助吗?

【问题讨论】:

    标签: asp.net-mvc itextsharp


    【解决方案1】:

    您在第一个方法中错误地使用了DocumentPdfWriter 类。我将在该方法中加入一些 cmets 以更好地解释发生了什么。

    public FileStreamResult pdf()
    {
        //Create a generic Stream for someone to write their bytes to
        MemoryStream workStream = new MemoryStream();
    
        //Create an iText Document helper object which is a friendly way to create new PDFs using things like tables and paragraphs.
        //No where in the code below will this helper object be used so that's the first problem.
        Document document = new Document();
    
        //Bind our document helper and stream to a PdfWriter.
        //This writer will _exclusively own_ the Stream from now on.
        //If _anyone_ else writes to the stream (as you are doing below) it will break the PDF or possibly just throw an exception
        PdfWriter.GetInstance(document, workStream).CloseStream = false;
    
        //Business logic here unrelated to the problem
        List<Plant> plants = new List<Plant>();
        foreach (var item in context.Plants)
        {
            plants.Add(item);
        }
    
        //Create a byte array that represents a PDF. The GeneratePdf appears to be correct.
        byte[] byteInfo = GeneratePdf(plants);
    
        //Even though we declared above that we want our PdfWriter to have exclusive access to the Stream,
        //ignore that and write our byte array to it.
        workStream.Write(byteInfo, 0, byteInfo.Length);
    
        //Rewind the stream
        workStream.Position = 0;
    
        return new FileStreamResult(workStream, "application/pdf");
    }
    

    希望这些 cmets 有意义。您的 GeneratePdf() 方法是制作 PDF 的原因。一旦你有了一个有效的 PDF,除非你想修改或检查它,否则你不再需要 iTextSharp。因此,您的第一种方法应更改为如下所示。 (我现在没有可用的 VS,但除了可能的一两个错字之外,这应该可以编译。)

        //Business logic
        List<Plant> plants = new List<Plant>();
        foreach (var item in context.Plants)
        {
            plants.Add(item);
        }
    
        //Create our PDF
        byte[] byteInfo = GeneratePdf(plants);
    
        //Wrap the bytes in a Stream and return
        using( var workStream = new MemoryStream( byteInfo ) )
        {
            return new FileStreamResult(workStream, "application/pdf");
        }
    

    【讨论】:

      【解决方案2】:

      您描述Exception 的方式是有根据的猜测,您的问题出在链接到您的控制器/操作的视图中。例如,如果您有一个 View 并且正在创建一个类似于评论部分的超链接:

      @* remove comment to see Exception
      <h2>Exception: "OutputStream is not available when a custom TextWriter is used."</h2>
      <p>
      <a href="@Html.Action("IndexPdf")">This throws an Exception</a>
      </p>
      *@
      
      <h2>Correct!</h2>
      <p>
      <a href="@Url.Action("IndexPdf")" target='_blank'>This works!</a>
      </p>
      

      您描述的确切异常被抛出:

      System.Web.HttpException:自定义时 OutputStream 不可用 使用了 TextWriter。

      所以使用Url.Action()

      除此之外,还有一些关于代码中GeneratePdf() 方法的注意事项:

      • 删除对MemoryStreamDocumentClose() 调用,因为它们都在using 语句中。
      • MemoryStream 调用移到ToArray() 之外的Document using 块之外。否则 PDF 结果可能会损坏。

      基于您的代码的简短示例:

      private static byte[] GeneratePdf(List<Plant> plants)
      {
          using (MemoryStream memoryStream = new MemoryStream())
          {
              using (var doc = new Document())
              {
                  PdfWriter.GetInstance(doc, memoryStream);
                  doc.Open();
                  doc.SetMargins(120, 120, 270, 270);
                  Paragraph pgTitle = new Paragraph("TEST");
                  doc.Add(pgTitle);
      
                  // initialize title, etc, here
                  // and iterate over plants here
              }
              // return **AFTER** Document is disposed
              return memoryStream.ToArray();
          }
      }
      

      还有一些关于你的 pdf() Action 的注释:

      • 可能是拼写错误或复制/粘贴错误,但没有理由 DocumentPdfWriter.GetInstance()
      • 如果您返回一个不太具体的 ActionResult 而不是 FileStreamResult,则不必在内存中制作 PDF 副本。 IE。你可以去掉MemoryStream,而是调用Controller.File(),因为第一个参数是一个字节数组:

      另一个基于您的代码的简短示例,这次是针对控制器操作:

      public ActionResult IndexPdf()
      {
          var plants = new List<Plant>();
          // get your plants here
          byte[] byteInfo = GeneratePdf(plants);
      
          return File(byteInfo, "application/pdf");
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-29
        • 2019-11-13
        • 2010-11-10
        • 1970-01-01
        • 2012-04-18
        • 2016-11-05
        • 1970-01-01
        • 2012-01-30
        相关资源
        最近更新 更多