我在我的控制器中有这两个方法。我想打开FilestreamResult pdf(),它返回一个文件流结果。但是,当使用自定义TextWriter时,我得到的OutputStream不可用。我正在使用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");
}
和Generate 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();
}
}
}
任何帮助?
答案 0 :(得分:2)
您在第一种方法中错误地使用了Document
和PdfWriter
类。我将对该方法提出一些意见,以便更好地解释发生了什么。
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");
}
希望这些评论有意义。您的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");
}
答案 1 :(得分:0)
您描述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()
方法的注释:
Close()
和MemoryStream
上的Document
来电,因为它们都在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
的一些说明:
Document
或PdfWriter.GetInstance()
ActionResult
而不是FileStreamResult
,则不必制作PDF的内存副本。即您可以删除MemoryStream
,而是调用Controller.File()
,因为第一个参数是字节数组:另一个基于代码的简短示例,这次是控制器操作:
public ActionResult IndexPdf()
{
var plants = new List<Plant>();
// get your plants here
byte[] byteInfo = GeneratePdf(plants);
return File(byteInfo, "application/pdf");
}