2

I am using Rotativa tool to display PDF. It works fine on localhost, But does not work on Azure platform.

Below is my code...

public ActionResult GeneratePDF(int id = 0)
    {
        ReportTransactionData reporttransactiondata = db.ReportTransactionDatas.Find(id);
        var viewFileToPrint = @"~/Views/ReportTranData/PDFReport.cshtml";
        //var oRotativaPDF = new Rotativa.ViewAsPdf();
        var oRotativaPDF = new Rotativa.PartialViewAsPdf();
        try
        {
            if (reporttransactiondata == null)
            {
                return HttpNotFound();
            }
            else
            {
                // Populate reporttransactiondata with Verfier Name...TO BE IMPLEMENTED LATER...
                //reporttransactiondata.VerifierName = GetVerifierNameByID(reporttransactiondata.VerifierID);
            }

            // Code to call a function/action...
            //return new Rotativa.ActionAsPdf("PrintRptInPDF", reporttransactiondata) 

            //oRotativaPDF = new Rotativa.ViewAsPdf(viewFileToPrint, reporttransactiondata)
            //        {
            //            FileName = "Technician Job Report.pdf",
            //            PageSize = Size.A4,
            //            PageOrientation = Orientation.Portrait,
            //            PageMargins = new Margins(0, 0, 0, 0),
            //            PageWidth = 230,      //250      //300  // 350
            //            PageHeight = 360,      // 380   // 400 //420  // 450
            //            CustomSwitches = "--disable-smart-shrinking"
            //        };

            oRotativaPDF = new Rotativa.PartialViewAsPdf(viewFileToPrint, reporttransactiondata)
            {
                FileName = "Technician Job Report.pdf",
                PageSize = Size.A4,
                PageOrientation = Orientation.Portrait,
                PageMargins = new Margins(0, 0, 0, 0),
                PageWidth = 230,      //250      //300  // 350
                PageHeight = 360,      // 380   // 400 //420  // 450
                CustomSwitches = "--disable-smart-shrinking"
            };
        }
        catch (Exception ex)
        {
            // TODO: Code here...
        }

        return oRotativaPDF;
    }

Please ignore the commented code. This works just fine but when I deploy my web application, the PDF file is not downloaded at client side and after some time my IE browser display 500 internal server error.

I explored the issue further and came to know that this error may be because wkhtmltopdf.exe does not execute on its own on Azure platform. So I came with the following solution with the help of some search on the net about the issue resolution...

public ActionResult GeneratePDF(int id = 0) { ReportTransactionData reporttransactiondata = db.ReportTransactionDatas.Find(id); string viewName = @"~/Views/ReportTranData/PDFReport.cshtml"; string wkhtmltopdfPath = Server.MapPath(@"~/Rotativa/"); string switches = string.Empty; try { if (reporttransactiondata == null) { return HttpNotFound(); }

            string fullPath = Server.MapPath(@"~/ApplicationFiles/TechnicianJobReport.pdf");
            FileInfo objFileInfo = new System.IO.FileInfo(fullPath);
            if (objFileInfo.Exists)
            {
                objFileInfo.Delete();
            }

            string sViewString = RenderRazorViewToString(viewName, reporttransactiondata);
            var byteArray = ConvertHTMLtoPDF(wkhtmltopdfPath, switches, sViewString);
            var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
            fileStream.Write(byteArray, 0, byteArray.Length);
            fileStream.Close();

            // Download file at client side...
            Response.Clear();
            Response.ClearContent();
            Response.ClearHeaders();
            Response.Charset = "UTF-8";
            Response.ContentEncoding = Encoding.UTF8;
            Response.AddHeader("Content-Disposition", "attachment; filename=" + Server.UrlEncode(objFileInfo.Name));
            Response.ContentType = "application/pdf";
            Response.WriteFile(objFileInfo.FullName);
            Response.End();

        }
        catch (Exception ex)
        {
            // Handle exception here and Log Error to file...
            Repositories.Repository objRepository = new Repositories.Repository();
            string sLogFilePath = Server.MapPath(@"~/ApplicationFiles/ErrorLogFile.txt");
            objRepository.LogErrorToFile(ex, sLogFilePath, this.ControllerContext.Controller.ToString());
        }

        return View(reporttransactiondata);
    }
    public string RenderRazorViewToString(string viewName, object model)
    {
        ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,viewName);
            var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);
            viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
            return sw.GetStringBuilder().ToString();
        }
    }

    /// <summary>
    /// Converts given URL or HTML string to PDF.
    /// </summary>
    /// <param name="wkhtmltopdfPath">Path to wkthmltopdf.</param>
    /// <param name="switches">Switches that will be passed to wkhtmltopdf binary.</param>
    /// <param name="html">String containing HTML code that should be converted to PDF.</param>
    /// <returns>PDF as byte array.</returns>
    private static byte[] ConvertHTMLtoPDF(string wkhtmltopdfPath, string switches, string html)
    {
        // switches:
        //     "-q"  - silent output, only errors - no progress messages
        //     " -"  - switch output to stdout
        //     "- -" - switch input to stdin and output to stdout
        switches = "-q " + switches + " -";

        // generate PDF from given HTML string, not from URL
        if (!string.IsNullOrEmpty(html))
            switches += " -";

        var proc = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = Path.Combine(wkhtmltopdfPath, "wkhtmltopdf.exe"),
                Arguments = switches,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                RedirectStandardInput = true,
                WorkingDirectory = wkhtmltopdfPath,
                CreateNoWindow = true
            }
        };
        proc.Start();

        // generate PDF from given HTML string, not from URL
        if (!string.IsNullOrEmpty(html))
        {
            using (var sIn = proc.StandardInput)
            {
                sIn.WriteLine(html);
            }
        }

        var ms = new MemoryStream();
        using (var sOut = proc.StandardOutput.BaseStream)
        {
            byte[] buffer = new byte[4096];
            int read;

            while ((read = sOut.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
        }

        string error = proc.StandardError.ReadToEnd();

        if (ms.Length == 0)
        {
            throw new Exception(error);
        }

        proc.WaitForExit();

        return ms.ToArray();
    }

But this again works fine on localhost but not on Azure server and gives the same 500 internal server error with no exception at all. Please see if anyone can help here. I am using this wkhtmltopdf exe because I can specify the height and width of the pdf according to my (half of A4 page size) paper size requirement. If there is any other option where I may not end up in the issue of executing an external exe or dll, please suggest that option too.

Paras Chaudhary
  • 117
  • 3
  • 10
  • Please provide a stack trace to help debugging. – Simon W Mar 09 '15 at 11:34
  • No stacktrace available. It's IE 500 server error. The application runs for about 45 seconds and then white IE page saying 500 server error. That is all I have. – Paras Chaudhary Mar 09 '15 at 14:07
  • Is this a website or webrole deployment? Try deploying with a web.config that switches off custom errors so you can view the stacktrace. – Simon W Mar 09 '15 at 20:52
  • AFAIK Rotativa runs an .exe (wkhtmltopdf.exe) Perhaps you have no permission to do that. Please copy & paste full exception stacktrace. – Fabrizio Accatino Mar 10 '15 at 08:56
  • This is a website deployment. I have switched of the custom errors in the web.config and also I am creating a exception log file but I do not get any error or stacktrace. The webpage runs for about 30-45 seconds and says 500 internal server error. How can I check the permission on a windows azure plateform folder? – Paras Chaudhary Mar 10 '15 at 16:18
  • If you want to avoid hosting Rotativa and thus wkhtltopdf.exe executable on your server/hosting you can try the online service (SaaS) http://RotativaHQ.com – Giorgio Bozio Feb 17 '16 at 13:01

3 Answers3

7

Like (#Fabrizio Accatino) wrote: Rotativa is running wkhtmltopdf.exe. It is located in "Rotativa" folder under the root of your project. So the issue could be:

  1. During the deployment - the Rotativa folder is not created (ensure that you've added the folder and the .exe in the project and set the property of the file as "copy always").
  2. There are missing libraries on the server (ensure that there are presented on the server - msvcp120.dll and msvcr120.dll /under sysWOW64 folder/)
  3. Ensure that the app pool user have the needed permissions to run the executable and to store the temp .pdf file.
  4. Ensure that the path name does not exceed the max length (250 digits I think).

I hope this will guide you for solving the problem.

peev
  • 302
  • 3
  • 13
  • 2
    Missing dll's can be installed from https://www.microsoft.com/en-GB/download/details.aspx?id=40784 (x86 version) – Glenn Vandamme Aug 15 '15 at 22:12
  • @peev Just to confirm, does this mean I have to commit the wkhtmltopdf.exe with the Rotativa folder into source control? If so, it seems a bit odd doing this as opposed to the nuget package restoring the required bits and pieces! – David Spence May 11 '16 at 11:22
0

I had the same problem, I managed to solve just by upgrading to the 1.6.3 version of rotating. Follow the link nuget: [https://www.nuget.org/packages/Rotativa/1.6.3] [1]


In the package Manager Console, type:

  1. Uninstall-Package Rotating press ENTER.
  2. Install-Package Rotating-Version 1.6.3 press ENTER.
  3. Check in the rotating folder, if you are now just the file * * wkhtmltopdf. exe * *.

Remark

In the 1.6.3 version the rotating no longer uses the files:

  1. libeay32. dll
  2. LIBGCC_S_DW2-1. dll
  3. MINGWM10. dll
  4. README. txt
  5. ssleay32. dll

It uses only the following file:

  1. wkhtmltopdf. exe

However, when upgrading to this new version, the rotating updates only this file wkhtmltopdf.exe to the new one, replacing it.

Now just rotate it again and it will work again.

[1]: Rotating upgrading to the 1.6.3 version

0

I think only premium accounts on azure allow to run wkhtmltopdf.exe on server or you can also create rotative pdf using this https://rotativahq.com/

Hope this help anyone !

Mustufa
  • 116
  • 4