MemoryStream PDF file in ASP.NET Core 2 - c#

Keep getting an error 'Cannot access a closed Stream.'
Does the file need to be physically saved on a server first, prior to being Streamed? I am doing the same with Excel file and it works just fine. Trying to use the same principle here with PDF file.
[HttpGet("ExportPdf/{StockId}")]
public IActionResult ExportPdf(int StockId)
{
string fileName = "test.pdf";
MemoryStream memoryStream = new MemoryStream();
// Create PDF document
Document document = new Document(PageSize.A4, 25, 25, 25, 25);
PdfWriter pdfWriter = PdfWriter.GetInstance(document, memoryStream);
document.Open();
document.Add(new Paragraph("Hello World"));
document.Close();
memoryStream.Position = 0;
return File(memoryStream, "application/pdf", fileName);
}

Are you using iText7? If yes, please add that tag onto your question.
using (var output = new MemoryStream())
{
using (var pdfWriter = new PdfWriter(output))
{
// You need to set this to false to prevent the stream
// from being closed.
pdfWriter.SetCloseStream(false);
using (var pdfDocument = new PdfDocument(pdfWriter))
{
...
}
var renderedBuffer = new byte[output.Position];
output.Position = 0;
output.Read(renderedBuffer, 0, renderedBuffer.Length);
...
}
}

Switched to iText& (7.1.1) version as per David Liang comment
Here is the code that worked for me, a complete method:
[HttpGet]
public IActionResult Pdf()
{
MemoryStream memoryStream = new MemoryStream();
PdfWriter pdfWriter = new PdfWriter(memoryStream);
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
Document document = new Document(pdfDocument);
document.Add(new Paragraph("Welcome"));
document.Close();
byte[] file = memoryStream.ToArray();
MemoryStream ms = new MemoryStream();
ms.Write(file, 0, file.Length);
ms.Position = 0;
return File(fileStream: ms, contentType: "application/pdf", fileDownloadName: "test_file_name" + ".pdf");
}

Related

How can i show a pdf on webbrowser using byte Array. C# [duplicate]

This question already has answers here:
How to return PDF to browser in MVC?
(11 answers)
Closed 8 months ago.
im trying to create a pdf file and im trying to return this file on imsonia or webbrowser, but i dont how to do this.
here is my code:
string beneficiarioRelatorio = "Test"
var stream = new MemoryStream();
PdfWriter writer = new PdfWriter(stream);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf);
//Paragraph header = new Paragraph(beneficiarioRelatorio);
document.Add(new Paragraph(beneficiarioRelatorio));
document.Close();
//return stream.ToArray();
//System.IO.File.WriteAllBytes("hello.pdf", stream.ToArray());
var teste = new FileStream(stream, FileMode.Open);
return new FileStreamResult(teste,"application/pdf");
try it
[HttpGet(Name = "GetPDF")]
public ActionResult GetPDF()
{
string beneficiarioRelatorio = "Test";
MemoryStream ms = new MemoryStream();
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
doc.Open();
doc.Add(new Paragraph(beneficiarioRelatorio));
doc.Close();
byte[] bytes = ms.ToArray();
return File(bytes, "application/pdf");
}

How to return PDF using iText

I am trying to return a PDF with simple text, but getting the following error when downloading the document: Failed to load PDF document. Any ideas on how to resolve this is appreciated.
MemoryStream ms = new MemoryStream();
PdfWriter writer = new PdfWriter(ms);
PdfDocument pdfDocument = new PdfDocument(writer);
Document document = new Document(pdfDocument);
document.Add(new Paragraph("Hello World"));
//document.Close();
//writer.Close();
ms.Position = 0;
string pdfName = $"IP-Report-{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.pdf";
return File(ms, "application/pdf", pdfName);
You have to close the writer without closing the underlying stream, which will flush its internal buffer. As is, the document isn't being written to the memory stream in its entirety. Everything but ms should be in a using, too.
You can verify this is occuring by checking the length of ms in your code vs. the code below.
When the using (PdfWriter writer =...) closes, it will close the writer, which causes it to flush its pending writes to the underlying stream ms.
MemoryStream ms = new MemoryStream();
using (PdfWriter writer = new PdfWriter(ms))
using (PdfDocument pdfDocument = new PdfDocument(writer))
using (Document document = new Document(pdfDocument))
{
/*
* Depending on iTextSharp version, you might instead use:
* writer.SetCloseStream(false);
*/
writer.CloseStream = false;
document.Add(new Paragraph("Hello World"));
}
ms.Position = 0;
string pdfName = $"IP-Report-{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.pdf";
return File(ms, "application/pdf", pdfName);

Convert html to pdf and merge it with existing pdfs

I have a System.Net.Mail.MailMessage which shall have it's html body and pdf attachments converted into one single pdf.
Converting the html body to pdf works for me with this answer
Converting the pdf attachments into one pdf works for me with this answer
However after ~10 hours of trying I can not come up with a combined solution which does both. All I'm getting are NullReferenceExceptions somewhere in IText source, "the document is not open", etc...
For example, this will throw no error but the resulting pdf will only contain the attachments but not the html email body:
Document document = new Document();
StringReader sr = new StringReader(mail.Body);
HTMLWorker htmlparser = new HTMLWorker(document);
using (FileStream fs = new FileStream(targetPath, FileMode.Create))
{
PdfCopy writer = new PdfCopy(document, fs);
document.Open();
htmlparser.Parse(sr);
foreach (string fileName in pdfList)
{
PdfReader reader = new PdfReader(fileName);
reader.ConsolidateNamedDestinations();
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfImportedPage page = writer.GetImportedPage(reader, i);
writer.AddPage(page);
}
PRAcroForm form = reader.AcroForm;
if (form != null)
{
writer.CopyAcroForm(reader);
}
reader.Close();
}
writer.Close();
document.Close();
}
I'm using the LGPL licensed ITextSharp 4.1.6
From v4.1.6 fanboy to v4.1.6 fanboy :D
Looks like the HTMLWorker is closing the documents stream right after parsing. So as a workaround, you could create a pdf from your mailbody in memory. And then add this one together with the attachment to your final pdf.
Here is some code, that should do the trick:
StringReader htmlStringReader = new StringReader("<html><body>Hello World!!!!!!</body></html>");
byte[] htmlResult;
using (MemoryStream htmlStream = new MemoryStream())
{
Document htmlDoc = new Document();
PdfWriter htmlWriter = PdfWriter.GetInstance(htmlDoc, htmlStream);
htmlDoc.Open();
HTMLWorker htmlWorker = new HTMLWorker(htmlDoc);
htmlWorker.Parse(htmlStringReader);
htmlDoc.Close();
htmlResult = htmlStream.ToArray();
}
byte[] pdfResult;
using (MemoryStream pdfStream = new MemoryStream())
{
Document doc = new Document();
PdfCopy copyWriter = new PdfCopy(doc, pdfStream);
doc.Open();
PdfReader htmlPdfReader = new PdfReader(htmlResult);
AppendPdf(copyWriter, htmlPdfReader); // your foreach pdf code here
htmlPdfReader.Close();
PdfReader attachmentReader = new PdfReader("C:\\temp\\test.pdf");
AppendPdf(copyWriter, attachmentReader);
attachmentReader.Close();
doc.Close();
pdfResult = pdfStream.ToArray();
}
using (FileStream fs = new FileStream("C:\\temp\\test2.pdf", FileMode.Create, FileAccess.Write))
{
fs.Write(pdfResult, 0, pdfResult.Length);
}
private void AppendPdf(PdfCopy writer, PdfReader reader)
{
for (int i = 1; i <= reader.NumberOfPages; i++)
{
PdfImportedPage page = writer.GetImportedPage(reader, i);
writer.AddPage(page);
}
}
Ofc you could directly use a FileStream for the final document instead of a MemoryStream as well.

convert a pdfreader to a pdfdocument

Can anyone tell me how to convert a PdfReader object into a PdfDocument ?
I have read a disk file and converted to a memorystream but I need it as a PdfDocument for other methods in my C# program.
I'm converting an application to use iTextSharp instead of PdfSharp.
MemoryStream pdfstream = new MemoryStream();
/* Convert the attachment to an byte array */
byte[] pdfarray = (byte[])dr["Data"];
/* Write the attachment into the memory */
pdfstream.Write(pdfarray, 0, pdfarray.Length);
/* Set the memorystream to the beginning */
pdfstream.Seek(0, System.IO.SeekOrigin.Begin);
/* Open the pdf document */
PdfSharp.Pdf.PdfDocument document = PdfSharp.Pdf.IO.PdfReader.Open(pdfstream, PdfDocumentOpenMode.Modify);
//iTextSharp.text.Document doc1 = iTextSharp.text.pdf.PdfReader.GetStreamBytes(
//ITS.pdf.PdfReader rdr = ITS.pdf.PdfReader(
string filename = DateTime.Now.Ticks.ToString() + "_" + dr["AttachmentName"].ToString();
string path = Path.Combine(FolderName, filename);
document.Save(path);
I think you can do something like this (note code not run or tested, might need a tweak):
using (MemoryStream ms = new MemoryStream())
{
Document doc = new Document(PageSize.A4, 50, 50, 15, 15);
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
using (var rdr = new PdfReader(filePath))
{
PdfImportedPage page;
for(int i = 1; i <= rdr.PageCount; i++)
{
page = writer.GetImportedPage(templateReader, i)
writer.DirectContent.AddTemplate(page, 0, 0);
doc.NewPage();
}
}
}
This will read in the PDF page by page and output it to your document.

Create PDF in memory instead of physical file

How do one create PDF in memorystream instead of physical file using itextsharp.
The code below is creating actual pdf file.
Instead how can I create a byte[] and store it in the byte[] so that I can return it through a function
using iTextSharp.text;
using iTextSharp.text.pdf;
Document doc = new Document(iTextSharp.text.PageSize.LETTER, 10, 10, 42, 35);
PdfWriter wri = PdfWriter.GetInstance(doc, new FileStream("c:\\Test11.pdf", FileMode.Create));
doc.Open();//Open Document to write
Paragraph paragraph = new Paragraph("This is my first line using Paragraph.");
Phrase pharse = new Phrase("This is my second line using Pharse.");
Chunk chunk = new Chunk(" This is my third line using Chunk.");
doc.Add(paragraph);
doc.Add(pharse);
doc.Add(chunk);
doc.Close(); //Close document
Switch the filestream with a memorystream.
MemoryStream memStream = new MemoryStream();
PdfWriter wri = PdfWriter.GetInstance(doc, memStream);
...
return memStream.ToArray();
using iTextSharp.text;
using iTextSharp.text.pdf;
Document doc = new Document(iTextSharp.text.PageSize.LETTER, 10, 10, 42, 35);
byte[] pdfBytes;
using(var mem = new MemoryStream())
{
using(PdfWriter wri = PdfWriter.GetInstance(doc, mem))
{
doc.Open();//Open Document to write
Paragraph paragraph = new Paragraph("This is my first line using Paragraph.");
Phrase pharse = new Phrase("This is my second line using Pharse.");
Chunk chunk = new Chunk(" This is my third line using Chunk.");
doc.Add(paragraph);
doc.Add(pharse);
doc.Add(chunk);
}
pdfBytes = mem.ToArray();
}
I've never used iTextPDF before but it sounded interesting so I took upon the challenge and did some research on my own. Here's how to stream the PDF document via memory.
protected void Page_Load(object sender, EventArgs e)
{
ShowPdf(CreatePDF2());
}
private byte[] CreatePDF2()
{
Document doc = new Document(PageSize.LETTER, 50, 50, 50, 50);
using (MemoryStream output = new MemoryStream())
{
PdfWriter wri = PdfWriter.GetInstance(doc, output);
doc.Open();
Paragraph header = new Paragraph("My Document") {Alignment = Element.ALIGN_CENTER};
Paragraph paragraph = new Paragraph("Testing the iText pdf.");
Phrase phrase = new Phrase("This is a phrase but testing some formatting also. \nNew line here.");
Chunk chunk = new Chunk("This is a chunk.");
doc.Add(header);
doc.Add(paragraph);
doc.Add(phrase);
doc.Add(chunk);
doc.Close();
return output.ToArray();
}
}
private void ShowPdf(byte[] strS)
{
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment; filename=" + DateTime.Now);
Response.BinaryWrite(strS);
Response.End();
Response.Flush();
Response.Clear();
}
Where your code has new FileStream, pass in a MemoryStream you've already created. (Don't just create it inline in the call to PdfWriter.GetInstance - you'll want to be able to refer to it later.)
Then call ToArray() on the MemoryStream when you've finished writing to it to get a byte[]:
using (MemoryStream output = new MemoryStream())
{
PdfWriter wri = PdfWriter.GetInstance(doc, output);
// Write to document
// ...
return output.ToArray();
}
I haven't used iTextSharp, but I suspect some of these types implement IDisposable - in which case you should be creating them in using statements too.

Categories