FilestreamResult 未打开
FilestreamResult not opening
我在我的 controller.I 中有这两种方法想要打开 returns 文件流 result.However 的 FilestreamResult pdf(),当自定义时我得到 OutputStream 不可用使用 TextWriter error.I 我正在使用 itextsharp for 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();
}
}
}
有什么帮助吗?
您在第一种方法中错误地使用了 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");
}
根据您描述 Exception
的方式,我有根据地猜测您的问题出在链接到您的 controller/action 的视图中。例如,如果您有一个 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 is not available when a custom
TextWriter is used.
所以使用Url.Action()
.
除此之外,关于代码中 GeneratePdf()
方法的几点说明:
- 删除对
MemoryStream
和 Document
的 Close()
调用,因为它们都在 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
:
- 可能是打字错误或 copy/paste 错误,但没有理由
Document
或 PdfWriter.GetInstance()
- 如果您 return 不太具体
ActionResult
而不是 FileStreamResult
,则不必制作 PDF 的 in-memory 副本。 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");
}
我在我的 controller.I 中有这两种方法想要打开 returns 文件流 result.However 的 FilestreamResult pdf(),当自定义时我得到 OutputStream 不可用使用 TextWriter error.I 我正在使用 itextsharp for 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();
}
}
}
有什么帮助吗?
您在第一种方法中错误地使用了 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");
}
根据您描述 Exception
的方式,我有根据地猜测您的问题出在链接到您的 controller/action 的视图中。例如,如果您有一个 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 is not available when a custom TextWriter is used.
所以使用Url.Action()
.
除此之外,关于代码中 GeneratePdf()
方法的几点说明:
- 删除对
MemoryStream
和Document
的Close()
调用,因为它们都在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
:
- 可能是打字错误或 copy/paste 错误,但没有理由
Document
或PdfWriter.GetInstance()
- 如果您 return 不太具体
ActionResult
而不是FileStreamResult
,则不必制作 PDF 的 in-memory 副本。 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");
}