Почему Rotativa всегда создает мою страницу входа? Почему это медленно?
Я использовал этот пример кода Rotativa 1.6.4 для создания PDF файла со страницы в приложении .NET MVC 5.
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();
}
Он не печатал страницу индекса, а вместо этого печатал мою страницу входа.
Как только я исправил проблему аутентификации, генерация PDF была чрезвычайно медленной даже с CustomSwitches
. (Несколько минут)
Вышеприведенный код может действительно работать для вас - он обошел проблему аутентификации с помощью свойства Cookies
, но для меня это было слишком медленным.
Как распечатать безопасную страницу, а также сделать это быстро?
Ответы
Ответ 1
Я боролся с этим, вероятно, 8 часов, и я отправляю свое собственное решение частично как самостоятельную ссылку, но также и потому, что не было хорошего ответа при переполнении стека.
Загрузите источник Rotativa
С открытым исходным кодом на github. Я пробовал много других решений, где люди говорили использовать UrlAsPdf
и другие решения из проблем github, но ничто из этого не сработало для меня. Еще одно преимущество, помимо чтения кода... Создайте файл pdb
, подбросьте его в свое решение и отлаживайте его. Это покажет много! Я обнаружил, что Rotativa использует wkhtmltopdf.exe
под обложками. Это использует веб-комплект для рендеринга html. Также команда обычно делает HTTP-запрос к URL-адресу. Зачем? Мы уже на сервере! Это означает, что нам пришлось бы повторно аутентифицировать и объяснять, почему мы иногда можем получить страницу входа. Копирование файлов cookie поможет, но зачем делать запрос http к себе, когда вы можете сделать это в режиме онлайн?
Прорыв
Я нашел метод расширения в источнике GetHtmlFromView
, который генерирует html представления без отдельного запроса http! ДА! Кто звонит GetHtmlFromView
? Почему ViewAsPdf
, конечно. Так что это привело меня к тому, чтобы попробовать код ниже, который работает и быстро!
Код для размещения в 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");
Ответ 2
У меня была такая же проблема, но ответ Джесса не помог мне.
Когда я обновил файл wkhtmltopdf.exe в своем проекте, скачанный с здесь, он снова работал быстро.
Ответ 3
Надеюсь, что этот код разрешит первый вопрос
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
};
}
Ответ 4
ViewAsPdf решил мою проблему. ActionAsPdf генерировать ошибку или генерировать страницу входа.
Dictionary<string, string> cookieCollection = new Dictionary<string, string>();
foreach (var key in Request.Cookies.AllKeys)
{
cookieCollection.Add(key, Request.Cookies.Get(key).Value);
}
var abc = new ViewAsPdf("invoice", _customers)
{
FileName = "Name.pdf",
Cookies = cookieCollection,
FormsAuthenticationCookieName = FormsAuthentication.FormsCookieName
};
var byteArray = abc.BuildPdf(ControllerContext);
var fileStream = new FileStream(Server.MapPath(subPath) + "/abc.pdf", FileMode.Create, FileAccess.Write);
fileStream.Write(byteArray, 0, byteArray.Length);
fileStream.Close();