Click here to Skip to main content
14,829,981 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have generated a pdf file from html and now I need to save it to a folder in my project.

I am able to get the generated pdf to download locally but when I send it to the file folder it gets corrupted and will not open.
This portion of the code allows a 170+KB pdf to be dropped, so pdf is being created.
Response.OutputStream.Write(memStream.GetBuffer(), 0, memStream.GetBuffer().Length);

the bold text below creates a 1KB file that cannot be opened as a pdf.
var fileStream = new FileStream(Server.MapPath("~/tempFiles/") + fileName, FileMode.CreateNew, FileAccess.Write);
memStream.Seek(0, SeekOrigin.Begin);
memStream.CopyTo(fileStream);
fileStream.Dispose();


What I have tried:

C#
  public void CreateHTML(ComplaintIntakeData cd)
{
  string formHtml = "<table class=\"MsoNormal\">";
  string complaintTypeHtml = PCSUtilities.GetComplaintTypeHTML(cd);
  string providerHtml = "";
  if (cd.Providers != null && cd.Providers.Count > 0)
  {
      providerHtml = PCSUtilities.GetProviderHTML(cd);
  }
        string facilityHtml = PCSUtilities.GetFacilityHTML(cd);
        string anonymousHtml = PCSUtilities.GetAnonymousHTML(cd);
        string contactHtml = PCSUtilities.GetContactHTML(cd);
        string patientHtml = PCSUtilities.GetPatientHTML(cd);
        string detailsHtml = PCSUtilities.GetComplaintDetailsHTML(cd);
        formHtml = formHtml + complaintTypeHtml + providerHtml + facilityHtml + anonymousHtml + contactHtml + patientHtml + detailsHtml + "</table>";
        formHtml = formHtml.Replace("''", "\"");
        // Load HTML template for letter and replace template fields with provider data
        string htmlContent = File.ReadAllText(Server.MapPath("~/ComplaintIntakeForm.html"));
        htmlContent = htmlContent.Replace("<%ComplaintInformation%>", formHtml);
        string fileName = "ComplaintIntakeFile_" + cd.ComplaintGuid.ToString() +".pdf";
        using (MemoryStream memStream = new MemoryStream())
        {
            try
            {
                // Load up a new PDF doc.
                iTextSharp.text.Document pdfDoc = new iTextSharp.text.Document(PageSize.LETTER);

                PdfWriter writer = PdfWriter.GetInstance(pdfDoc, memStream);

                // writer.CompressionLevel = PdfStream.NO_COMPRESSION;

                // Make document tagged PDFVERSION_1_7 
                writer.SetPdfVersion(PdfWriter.PDF_VERSION_1_7);
                writer.SetTagged();

                // Set document metadata
                writer.ViewerPreferences = PdfWriter.DisplayDocTitle;
                pdfDoc.AddLanguage("en-US");
                pdfDoc.AddTitle("Complaint Intake Form");
                writer.CreateXmpMetadata();

                pdfDoc.Open();

                var tagProcessors = (DefaultTagProcessorFactory)Tags.GetHtmlTagProcessorFactory();
                //tagProcessors.RemoveProcessor(HTML.Tag.IMG);
                //tagProcessors.AddProcessor(HTML.Tag.IMG, new CustomImageTagProcessor());

                var cssFiles = new CssFilesImpl();
                cssFiles.Add(XMLWorkerHelper.GetInstance().GetDefaultCSS());
                var cssResolver = new StyleAttrCSSResolver(cssFiles);
                var charset = Encoding.UTF8;
                var context = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
                context.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(tagProcessors);
                var htmlPipeline = new HtmlPipeline(context, new PdfWriterPipeline(pdfDoc, writer));
                var cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
                var worker = new XMLWorker(cssPipeline, true);
                var xmlParser = new XMLParser(true, worker, charset);

                try
                {
                    using (var sr = new StringReader(htmlContent))
                    {
                        xmlParser.Parse(sr);
                       // xmlParser.Flush();

                    }
                }
                catch (Exception e)
                {
                    Response.Write(e.Message);
                }
                try
                    {
                        var fileStream = new FileStream(Server.MapPath("~/tempFiles/") + fileName, FileMode.CreateNew, FileAccess.Write);
                        memStream.Seek(0, SeekOrigin.Begin);
                        memStream.CopyTo(fileStream);
                        fileStream.Dispose();
                    }                    
                    catch (Exception ex)
                    {
                        System.Windows.Forms.MessageBox.Show("The following error occurred:\n" + ex.ToString());
                    }
                pdfDoc.Close();

                //writer.Close();
                ///this creates a pdf download.
                Response.ContentType = "application/pdf";
                Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
                Response.OutputStream.Write(memStream.GetBuffer(), 0, memStream.GetBuffer().Length);
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("The following error occurred:\n" + ex.ToString());
            }

        }
}
Posted
Updated 10-Feb-21 8:34am

The PDF content is buffered in memory, and doesn't get flushed to the underlying stream until the buffer is full, or the Close method is called.

Move the pdfDoc.Close(); line above the code that saves the file:
C#
pdfDoc.Close();

using (var fileStream = new FileStream(Server.MapPath("~/tempFiles/") + fileName, FileMode.CreateNew, FileAccess.Write))
{
    memStream.Seek(0, SeekOrigin.Begin);
    memStream.CopyTo(fileStream);
}
NB: This is an ASP.NET application. You cannot use MessageBox.Show to show messages to the user.

It might appear to work when you debug the code in Visual Studio. But that's only because, in the specific case, the server and the client are the same machine.

As soon as you deploy your code to a real server, the code will stop working. In the best case, MessageBox.Show will throw an exception telling you that it cannot be used in a non-interactive process. In the worst case, the message will appear on the server, where nobody will ever see it, and your code will hang waiting for someone to log in to the server and acknowledge thousands of messages.

NB2: MemoryStream.GetBuffer()[^] returns the raw buffer, which will contain unused bytes. Do not use it to copy the memory stream content to the response, otherwise you will end up with a corrupt file.
C#
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
memStream.Seek(0, SeekOrigin.Begin);
memStream.CopyTo(Response.OutputStream);
   
v2
Comments
jmrobbins 9-Feb-21 12:33pm
   
I have implemented your suggestion, unfortunately moving the pdfDoc.Close() above the suggested code causes an error that it cannot access a closed stream.
Solved: I replaced the memStream variable in the PdfWriter code with the new FileStream and removed the using filestream code all together.
PdfWriter writer = PdfWriter.GetInstance(pdfDoc, new FileStream(Server.MapPath(path)+"/" + fileName, FileMode.CreateNew));
   

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900