I am trying to download multiple pdf's as attachments in my asp.net application.I have created some templates and filling values using pdfstamper(itextsharp). I am able to fill the values but not able to download.
private void FillForm(string path, DataTable BridgeValues, DataTable Comments, DataTable Maintenance,string Newfilename)
{
try
{
string pdfTemplate = path;
string newFile = Newfilename;
string Pathser = "";
if (!System.IO.Directory.Exists(Server.MapPath(#"~/PDF/")))
{
System.IO.Directory.CreateDirectory(Server.MapPath(#"~/PDF/"));
}
if (Directory.Exists(Server.MapPath(#"~/PDF/")))
{
Pathser = Server.MapPath(#"~/PDF/" + Newfilename);
}
System.IO.MemoryStream mStream = new System.IO.MemoryStream();
// create a new PDF reader based on the PDF template document
PdfReader pdfReader = new PdfReader(pdfTemplate);
PdfStamper pdfStamper = new PdfStamper(pdfReader, new FileStream(Pathser, FileMode.Create));
AcroFields pdfFormFields = pdfStamper.AcroFields;
DataColumn dc = null;
for (int i = 0; i < BridgeValues.Columns.Count - 1; i++)
{
dc = BridgeValues.Columns[i];
pdfFormFields.SetField(dc.ColumnName.ToString(), BridgeValues.Rows[0][dc].ToString());
}
pdfStamper.FormFlattening = true;
// close the pdf
pdfStamper.Close();
////Response.ContentType = "application/octet-stream";
Response.ContentType = "application/pdf";
////Response.AddHeader("Content-Disposition", "attachment; filename=Report.pdf");
Response.AddHeader("Content-Disposition", "attachment; filename=" + Newfilename + "");
////Response.BinaryWrite(mStream.ToArray());
Response.TransmitFile(Server.MapPath(("~/PDF/"+ Newfilename)));
Response.Clear();
Response.End();
}
catch (System.Threading.ThreadAbortException lException)
{
// do nothing
}
}
First time I tried to create one pdf ,it worked but later when I tried to download multiple files it gave an execption.
Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.
I don't think you can download multiple files by making one request and returning a collection from the action. I would suggest that it you need to allow user to download multiple files you ZIP them and stream the archive down to the browser.
Here is an example of zipping multiple files: http://devpinoy.org/blogs/keithrull/archive/2008/01/25/how-to-create-zip-files-in-c-with-sharpziplib-ziplib.aspx
Related
I've developed a pdf file using itextsharp.
Pdf generation is working fine. After the pdf is created it's being downloaded.
My problem is when the user clicks on Generate PDF button , Pdf is generated and downloaded properly but postback doesn't occurs.
I want the postback to be occured because I want to Reset my Form after Pdf is generated that is Clear All Fields .
How Can I do this ?
Here is my code :
Method to Generate PDF :
public void GetPDF(string quote_num)
{
string url = FilesPath.Path_SaveFile + Session["empcd"].ToString() +"-Quotation.pdf";
Document disclaimer = new Document(PageSize.A4, 2, 2, 10, 10);
PdfWriter writer = PdfWriter.GetInstance(disclaimer, new FileStream(url, FileMode.Create));
writer.PageEvent = new myPDFpgHandler(quote_num);
disclaimer.SetMargins(70, 10, 60, 80);
disclaimer.Open();
GenerateQuotPDF getpdf = new GenerateQuotPDF();
disclaimer = getpdf.GetPDFparams(disclaimer,quote_num, Session["empcd"].ToString(),txt_contactperson.Text,txt_contact1.Text,txt_company.Text,txt_address.Text,ddl_gene_desc.SelectedItem.ToString(),ddl_canopy.SelectedItem.ToString(),ddl_gene_type.SelectedItem.ToString(),txt_rentalamount.Text,txt_hours.Text,txt_variable.Text,ddl_terms.SelectedItem.ToString(),txt_remarks.Text,txt_technical.Text,ddl_sign1.SelectedValue,ddl_sign2.SelectedValue,txt_designation.Text,DateTime.Now);
disclaimer.Close();
System.IO.FileInfo file = new System.IO.FileInfo(url);
if (file.Exists)
{
WebClient client = new WebClient();
Byte[] buffer = client.DownloadData(url);
Response.AddHeader("content-disposition", "attachment; filename=" + Session["empcd"].ToString() + "-Quotation.pdf");
Response.AddHeader("content-length", buffer.Length.ToString());
Response.ContentType = "application/pdf";
Response.BinaryWrite(buffer);
}
}
Generate PDF Button Code :
protected void btn_submit_Click(object sender, EventArgs e)
{
if (IsValidQuotation())
{
string newQuotNum = rental_quotations.GetNewQuotNumber();
rental_quotations.AddNewQuotation(newQuotNum, Session["empcd"].ToString(), ddl_gene_type.SelectedValue.ToString(), ddl_gene_desc.SelectedValue, ddl_canopy.SelectedValue, txt_company.Text, txt_address.Text, txt_contactperson.Text, txt_designation.Text, txt_contact1.Text, txt_contact2.Text, txt_rentalamount.Text, ddl_terms.SelectedValue, txt_hours.Text, txt_variable.Text, txt_remarks.Text,ddl_sign1.SelectedValue,ddl_sign2.SelectedValue,txt_technical.Text);
GetPDF(newQuotNum);
ClearAllFields(); //this is not working
}
}
Postback is occurring since the file is being created. Try the given solution. Your GetPDF(string quote_num) function is doing two tasks that you should break into two functions.
Creating the pdf document.
Downloading the pdf file after it is done.
Now, After you have created the document, you should clear the controls and then send the file as response. Therefore do it as follows:
Create pdf file.
public void CreatePDF(string quote_num)
{
string url = FilesPath.Path_SaveFile + Session["empcd"].ToString() +"-Quotation.pdf";
Document disclaimer = new Document(PageSize.A4, 2, 2, 10, 10);
PdfWriter writer = PdfWriter.GetInstance(disclaimer, new FileStream(url, FileMode.Create));
writer.PageEvent = new myPDFpgHandler(quote_num);
disclaimer.SetMargins(70, 10, 60, 80);
disclaimer.Open();
GenerateQuotPDF getpdf = new GenerateQuotPDF();
disclaimer = getpdf.GetPDFparams(disclaimer,quote_num, Session["empcd"].ToString(),txt_contactperson.Text,txt_contact1.Text,txt_company.Text,txt_address.Text,ddl_gene_desc.SelectedItem.ToString(),ddl_canopy.SelectedItem.ToString(),ddl_gene_type.SelectedItem.ToString(),txt_rentalamount.Text,txt_hours.Text,txt_variable.Text,ddl_terms.SelectedItem.ToString(),txt_remarks.Text,txt_technical.Text,ddl_sign1.SelectedValue,ddl_sign2.SelectedValue,txt_designation.Text,DateTime.Now);
disclaimer.Close();
}
Reset the controls.
ClearAllFields();
Send the file as response.
public void SendPDF(string url)
{
System.IO.FileInfo file = new System.IO.FileInfo(url);
if (file.Exists)
{
WebClient client = new WebClient();
Byte[] buffer = client.DownloadData(url);
Response.AddHeader("content-disposition", "attachment; filename=" + Session["empcd"].ToString() + "-Quotation.pdf");
Response.AddHeader("content-length", buffer.Length.ToString());
Response.ContentType = "application/pdf";
Response.BinaryWrite(buffer);
Response.End();
}
}
Note that I also added Response.End() to clear the buffer.
I have a web page in my website that allows me to download the chart from that page and add it to an excel sheet. However, a red x button with the words: "this image cannot currently be displayed" is shown in place of the chart. I have tried many solutions online but all of them show the same outcome.
Here are my codes:
protected void ExcelDl_Click(object sender, EventArgs e) {
string tmpChartName = "test2.jpg";
string imgPath = HttpContext.Current.Request.PhysicalApplicationPath + tmpChartName;
Chart1.SaveImage(imgPath);
string imgPath2 = Request.Url.GetLeftPart(UriPartial.Authority) + VirtualPathUtility.ToAbsolute("~/" + tmpChartName);
Response.Clear();
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", "attachment; filename=test.xls;");
StringWriter sw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(sw);
string headerTable = #"<Table><tr><td><img src='" + imgPath2 + #"' \></td></tr></Table>";
Response.Write(headerTable);
Response.Write(sw.ToString());
Response.End();
}
Any form of help will be greatly appreciated. Also, do note that I have added the required codes in my Web.config.
We have tried your program and here it’s working fine. Excel downloaded along with image. I have installed in iis and tried with many client machine and it was working fine.
Not sure what’s going on your end. The problem might be wrong image path reference will cause this problem. Print image URL and make sure whether it is correct or not.
Alternate method: instead of using html tags inside the excel cell use XML closing method to render the image inside the excel cell.
Here I have added sample code for the Closed XML methods to render the image in excel. to use this code need to refer the following DLLs
1. ClosedXML.dll
2. WindowsCore.dll
3. DocumentFormat.OpenXML.dll
4. PresentationCore.dll
Reference Link for Closed XML methods: https://closedxml.codeplex.com/
using (XLWorkbook wb = new XLWorkbook())
{
IXLWorksheet WorkSheet = new IXLWorksheet();
string LogoPath = Server.MapPath("~/App_Themes/Images/logonew.png");
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(LogoPath);
if (bitmap != null)
{
var stream = new System.IO.MemoryStream();
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Gif);
if (stream != null)
{
stream.Position = 0;
XLPicture pic = new XLPicture
{
NoChangeAspect = true,
NoMove = true,
NoResize = true,
ImageStream = stream,
Name = "Logo",
EMUOffsetX = 4,
EMUOffsetY = 6
};
XLMarker fMark = new XLMarker
{
ColumnId = 1,
RowId = 1
};
pic.AddMarker(fMark);
WorkSheet.AddPicture(pic);
}
}
Response.Clear();
Response.Buffer = true;
Response.Charset = "";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=test.xls");
using (MemoryStream MyMemoryStream = new MemoryStream())
{
wb.SaveAs(MyMemoryStream);
MyMemoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
}
Please check and let me know your comments.
This is my code which is used in a wcf service. It successfully generates the PDF, but after generating the document, the folder in which the PDF is generated gives the error: "access is denied"
The PDF is closed for the website, but for the continuous web service it is not closed.
string r = builder.ToString();
string pdfname = Fuhre + "_" + ProtokolType + "_" + GeraeteNr + "_" + r;
PdfWriter.GetInstance(document, new FileStream(#"C:\inetpub\wwwroot\protokoll_pdfs\"+pdfname+".pdf",FileMode.Create));
document.Open();
WebClient wc = new WebClient();
string htmlText = html;
//Response.Write(htmlText);
List<IElement> htmlarraylist = HTMLWorker.ParseToList(new StringReader(htmlText), null);
for (int k = 0; k < htmlarraylist.Count; k++)
{
document.Add((IElement)htmlarraylist[k]);
}
pdflink1 = pdfname + ".pdf";
htmlpdflink =""+pdflink1;
document.Close();
You need to be careful to dispose of everything.
using(var filesStream = new FileStream())
{
using(PdfWriter wri = PdfWriter.GetInstance(doc, fileStream))
{
...
}
}
There are a few other objects (Stream, Document) you may want to close. A sample of how to perform the operation is shown below.
FileStream stream = new FileStream(filePath, FileMode.CreateNew);
Document doc = new Document(PageSize.A4, 24, 24, 24, 24);
PdfWriter writer = PdfWriter.GetInstance(doc, stream);
doc.Open();
//PDF writing operations here
writer.Flush();
doc.Close();
writer.Close();
stream.Close();
You want to serve a file to a browser and/or you want to save the file on disk.
In that case, you would benefit from creating the file in memory and then send the bytes to the browser as well as to a file on disk. This is explained in the answer to the following question: Pdf file not loading properly created by the servlet
The answer mentioned above is written in Java, so you'll have to adapt it.
You can do so by looking at other examples. For instance: Create PDF in memory instead of physical file
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();
}
Now you can write the pdfBytes to the Response object in your web application:
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();
}
And you can reuse the bytes to write them to a File: Can a Byte[] Array be written to a file in C#?
File.WriteAllBytes(string path, byte[] bytes)
If the problem persist, then you know that it isn't caused by iTextSharp, because iTextSharp merely produces the bytes.
In addition to what everyone else said, I strongly recommend you break each process into multiple sections that don't interact and aren't even aware of each other. Then test each section independently as much as possible. For instance:
private void makePDF( filePath )
{
//Create the PDF
}
private void main()
{
//Make the PDF
makePDF( "test.pdf" );
//If this line fails then your makePDF code has an open handle
File.Delete( "test.pdf" );
}
Then continue:
private void makePDF( filePath )
{
//Create the PDF
}
private void emailPDF( filePath )
{
//Email the PDF
}
private void main()
{
//Make the PDF
makePDF( "test.pdf" );
emailPDF( "test.pdf" );
//If this line fails now then your emailPDF code has an open handle
File.Delete( "test.pdf" );
}
The important part if that you don't try 500 things all at once because that leads to "something is locking my file but I don't know what".
I have successfully implemented the iTextSharp.text.pdf to populate a PDF template file we have setup. Currently that file is being save automatically to a specific folder on local machine...but we don't want that, we want the populated PDF to be saved by the user to the folder of their choice on their pc. We do not want to keep any of these files on the server once this application gets published.
the below code creates the hardcoded file path and it is populated, but the portion at the bottom that prompts the user to save the file, creates a pdf with the file name format we want, but the file is always 20k and wont open. How can I change the below code to not actually create the file on the server, but to create it to the users pc when they chose to save it?
using (FileStream outfile = new FileStream(outputfile, FileMode.Create))
{
PdfReader rdr = new PdfReader(pdftemplate);
PdfStamper stm = new PdfStamper(rdr, outfile);
AcroFields fields = stm.AcroFields;
foreach (var de in rdr.AcroFields.Fields)
{
if (de.Key == "Date")
{
fields.SetField("Date", dt.Rows[0]["Form Date"].ToString());
}
if (de.Key == "Project Name")
{
fields.SetField("Project Name", dt.Rows[0]["Project Name"].ToString());
}
if (de.Key == "Contract No")
{
fields.SetField("Contract No", dt.Rows[0]["Contract Number"].ToString());
}
}
stm.Close();
rdr.Close();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment; filename=" + newFile);
Response.Write(outfile);
Response.End();
}
I think the problem with your code is that you are using filestream which is causing the pdf to be saved to your server. Using memorystream should fix this. Try something like this and see if it helps.
Using (MemoryStream ms = new MemoryStream())
{
PdfReader rdr = new PdfReader(pdftemplate);
PdfStamper stm = new PdfStamper(rdr, ms);
AcroFields fields = stm.AcroFields;
foreach (var de in rdr.AcroFields.Fields)
{
if (de.Key == "Date")
{ fields.SetField("Date", dt.Rows[0]["Form Date"].ToString()); }
if (de.Key == "Project Name")
{ fields.SetField("Project Name", dt.Rows[0]["Project Name"].ToString()); }
if (de.Key == "Contract No")
{ fields.SetField("Contract No", dt.Rows[0]["Contract Number"].ToString()); }
}
stm.Close();
rdr.Close();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment; filename=MyFile.pdf");
//To display pdf in the browser window instead of saving, change attachment to inline
Response.BinaryWrite(ms.ToArray());
Response.End();
}
By using MemoryStream along with html headers, you should get a prompt to save the file.
I have a button when clicked, inserts text into form fields in a pdf and saves the filled pdf to a directory. When I am done editing the pdf, I want to open the pdf in the browswer, but Process.Start() is not working. Is there better way to immediately show the pdf after it has been generated? Here is the code for the button:
protected void btnGenerateQuote_Click(object sender, EventArgs e)
{
string address = txtAddress.Text;
string company = txtCompany.Text;
string outputFilePath = #"C:\Quotes\Quote-" + company + "-.pdf";
PdfReader reader = null;
try
{
reader = new PdfReader(#"C:\Quotes\Quote_Template.pdf");
using (FileStream pdfOutputFile = new FileStream
(outputFilePath, FileMode.Create))
{
PdfStamper formFiller = null;
try
{
formFiller = new PdfStamper(reader, pdfOutputFile);
AcroFields quote_template = formFiller.AcroFields;
//Fill the form
quote_template.SetField("OldAddress", address);
//Flatten - make the text go directly onto the pdf
// and close the form.
//formFiller.FormFlattening = true;
}
finally
{
if (formFiller != null)
{
formFiller.Close();
}
}
}
}
finally
{
reader.Close();
}
//Process.Start(outputFilePath); // does not work
}
Since this is about ASP.NET according to the tags, you should not use Process.Start() but for example code like this:
private void respondWithFile(string filePath, string remoteFileName)
{
if (!File.Exists(filePath))
throw new FileNotFoundException(
string.Format("Final PDF file '{0}' was not found on disk.",
filePath));
var fi = new FileInfo(filePath);
Response.Clear();
Response.AddHeader("Content-Disposition",
String.Format("attachment; filename=\"{0}\"",
remoteFileName));
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(fi.FullName);
Response.End();
}
And this would make the browser give the save/open dialog.