Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Rotativa always generate my login page? Why is it slow?

I was using this Rotativa 1.6.4 code example to generate a PDF from a page in my .NET MVC 5 app.

public ActionResult PrintIndex()
{
    var a = new ActionAsPdf("Index", new { name = "Giorgio" }) { FileName = "Test.pdf" };
    a.Cookies = Request.Cookies.AllKeys.ToDictionary(k => k, k => Request.Cookies[k].Value);
    a.FormsAuthenticationCookieName = System.Web.Security.FormsAuthentication.FormsCookieName;
    a.CustomSwitches = "--load-error-handling ignore";
    return a;
}

public ActionResult Index(string name)
{
    ViewBag.Message = string.Format("Hello {0} to ASP.NET MVC!", name);

    return View();
}

It was not printing the Index page, but instead was printing my login page.

Once I fixed the authentication issue, PDF generation was extremely slow even with CustomSwitches. (Several minutes)

The above code might actually work for you - it got around the authentication issue using the Cookies property, but it was way too slow for me.

How do I print a secure page as well as do it quickly?

like image 930
Jess Avatar asked Jan 28 '16 16:01

Jess


2 Answers

I struggled with this for probably 8 hours and I am posting my own solution partly as a self reference, but also because there was no good answer in stack overflow.

Download the Rotativa Source

It's open source on github. I tried lots of other solutions where people said to use UrlAsPdf and other solutions from github issues, but none of this worked for me. Another advantage besides reading the code... Build the pdb file, toss it into your solution and debug into it. It will reveal a lot! One thing I found is that Rotativa uses wkhtmltopdf.exe under the covers. This uses web kit to render the html. Also the command usually makes an http request to a url. Why? We are already on the server! That means we would have to re-authenticate and explains why we can sometimes get the Login page. Copying cookies will help, but why make an http request to yourself when you can do it in-line?

Breakthrough

I found an extension method in the source GetHtmlFromView which generates the view html without making a separate http request! YES! Who calls GetHtmlFromView? Why ViewAsPdf of course. So this lead me to try the below code, which works and is fast!

Code to put into an ASP.NET MVC Controller Action:

// ViewAsPdf calls Rotativa.Extensions.ControllerContextExtensions.GetHtmlFromView
// Which generates the HTML inline instead of making a separate http request which CallDriver (wkhtmltopdf.exe) does.
var a = new ViewAsPdf();
a.ViewName = "Index";
a.Model = _service.GetMyViewModel(id);
var pdfBytes = a.BuildPdf(ControllerContext);

// Optionally save the PDF to server in a proper IIS location.
var fileName = string.Format("my_file_{0}.pdf", id);
var path = Server.MapPath("~/App_Data/" + fileName);
System.IO.File.WriteAllBytes(path, pdfBytes);

// return ActionResult
MemoryStream ms = new MemoryStream(pdfBytes);
return new FileStreamResult(ms, "application/pdf");
like image 114
Jess Avatar answered Dec 01 '22 00:12

Jess


I hope this code solve first question

public ActionResult DownloadViewPDF() {
 Dictionary<string, string> cookieCollection = new Dictionary<string, string>();
   foreach (var key in Request.Cookies.AllKeys)
     {
       cookieCollection.Add(key, Request.Cookies.Get(key).Value);
     }
     return new ActionAsPdf("Index")
       {
          FileName = "Name.pdf",
          Cookies = cookieCollection
        };
     }
like image 38
Md. Anwar Hossain Avatar answered Nov 30 '22 22:11

Md. Anwar Hossain