Thursday, May 27, 2021

MVC download pdf generated from a view iText

 This is a little tricky as it involves converting html to pdf by using a tool such as iText. 

To generate the html I used a normal view like:

public ActionResult PdfView(int id)

{

    var entity = db.Customers.Find(id);

    return View(entity);   

}

Then I added a utility class which converts html to pdf using iText library

public class PdfCreator

    {

        public static byte[] ConvertToPdf(string html, string baseUri)

        {

 LicenseKey.LoadLicenseFile(HttpContext.Current.Server.MapPath(@"~/iText7/itextkey_0.xml"));

            ConverterProperties properties = new ConverterProperties();

            // Add solely one Typeface, Helevetica.

            FontProvider fp;

            properties = new ConverterProperties();

            var Helvetica = FontProgramFactory.CreateFont(StandardFonts.HELVETICA);

            var HelveticaBold = FontProgramFactory.CreateFont(StandardFonts.HELVETICA_BOLD);

            var HelveticaOblique = FontProgramFactory.CreateFont(StandardFonts.HELVETICA_OBLIQUE);

            var HelveticaBoldItalic = FontProgramFactory.CreateFont(StandardFonts.HELVETICA_BOLDOBLIQUE);

            fp = new FontProvider();

            fp.AddFont(Helvetica);

            fp.AddFont(HelveticaBold);

            fp.AddFont(HelveticaOblique);

            fp.AddFont(HelveticaBoldItalic);

            properties.SetFontProvider(fp);

            properties.SetBaseUri(baseUri);

            using (MemoryStream memoryStream = new MemoryStream())

            {

                PdfWriter writer = new PdfWriter(memoryStream);

                writer.SetCompressionLevel(CompressionConstants.BEST_COMPRESSION);

 

                // This is a crucial call. Otherwise, when we close the document, as we must do, the PDF created contains errors.

                writer.SetCloseStream(false);

 

                PdfDocument pdf = new PdfDocument(writer);

                pdf.SetDefaultPageSize(PageSize.A4);

               

                using (Document document = HtmlConverter.ConvertToDocument(html, writer, properties))

                {

                    document.SetMargins(100,100,100,100);

                }

                memoryStream.Seek(0, SeekOrigin.Begin);

                return memoryStream.ToArray();

            }

        }

    }

Next, I added another method with return type FileResult which converts this view's html to pdf and writes it to the response stream.


public FileResult DownloadPdf(int id)

        {

            var controllerContext = this.ControllerContext;

            var result = ViewEngines.Engines.FindView(controllerContext, "PdfView", null);

            ViewDataDictionary viewData = new ViewDataDictionary();

            viewData.Model = db.Entities.Find(id);

            StringWriter output;

            using (output = new StringWriter())

            {

                var viewContext = new ViewContext(controllerContext, result.View, viewData, controllerContext.Controller.TempData, output);

                result.View.Render(viewContext, output);

                result.ViewEngine.ReleaseView(controllerContext, result.View);

            }

 

            string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority + Request.ApplicationPath.TrimEnd('/') + "/Content";

            byte[] fileBytes = PdfCreator.ConvertToPdf(output.ToString(), baseUrl);

            string fileName = string.Format("Entity_{0}", id.ToString());

            return File(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);

        }


References:

  1. https://stackoverflow.com/questions/30121340/how-to-return-a-pdf-in-an-action-result-in-mvc
  2. https://stackoverflow.com/questions/21994933/open-pdf-in-new-tab-c-sharp
  3. https://itextpdf.com/en/products/itext-7/convert-html-css-to-pdf-pdfhtml
  4. https://stackoverflow.com/questions/18442343/get-html-from-mvc-4-view-into-a-string


No comments:

c# httpclient The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch

 If we get this error while trying to get http reponse using HttpClient object, it could mean that certificate validation fails for the remo...