asp.net - from - Convierta HTML a PDF en MVC con iTextSharp en MVC Razor
itextsharp pdf from html string (9)
Estoy intentando convertir HTML a PDF con iTextSharp
en MVC Razor, pero todo lo que he intentado no ha funcionado. ¿Alguien sabe cómo lograr esto?
Aquí es cómo implementas esta solución usando el motor Razor NO con el extraño <itext..
markup.
De esta manera, usted tiene control total sobre la presentación en pdf utilizando la salida html estándar.
El proyecto con una solución de ejemplo y código fuente está disponible aquí con instrucciones de instalación de nuget:
https://github.com/andyhutch77/MvcRazorToPdf
Install-Package MvcRazorToPdf
Esto también utiliza la nueva licencia de itextsharp, por lo que no sufre de ninguno de los aspectos negativos mencionados en las otras respuestas.
Aquí puede encontrar un enfoque diferente en caso de que desee escribir XML simple, lo encuentro mucho más simple y ligero.
http://www.codeproject.com/Articles/260470/PDF-reporting-using-ASP-NET-MVC3
Debería revisar RazorPDF que utiliza iText para generar el PDF, pero de una manera más amigable.
En caso de que esté utilizando ASP.NET Core e iTextSharp no es tan importante para usted, aquí está mi solución utilizando PhantomJS: http://nikolay.it/Blog/2018/03/Generate-PDF-file-from-Razor-view-using-ASP-NET-Core-and-PhantomJS/37
Obtener cadena HTML desde una vista de Razor
Este paso es bastante sencillo. Hay un servicio llamado IRazorViewEngine
en ASP.NET Core que se puede inyectar y luego usar para obtener la vista. Después de proporcionar la vista con ViewDataDictionary
y ActionContext
predeterminados, podemos solicitar que la vista se represente en StringWriter
que se puede convertir fácilmente en una cadena. Aquí está el código listo para usar para obtener una cadena del archivo de vista de Razor dado:
public interface IViewRenderService
{
Task<string> RenderToStringAsync(string viewName, object model);
}
public class ViewRenderService : IViewRenderService
{
private readonly IRazorViewEngine razorViewEngine;
private readonly ITempDataProvider tempDataProvider;
private readonly IServiceProvider serviceProvider;
public ViewRenderService(
IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
this.razorViewEngine = razorViewEngine;
this.tempDataProvider = tempDataProvider;
this.serviceProvider = serviceProvider;
}
public async Task<string> RenderToStringAsync(string viewName, object model)
{
var httpContext = new DefaultHttpContext { RequestServices = this.serviceProvider };
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using (var sw = new StringWriter())
{
var viewResult = this.razorViewEngine.GetView(null, viewName, false);
if (viewResult.View == null)
{
throw new ArgumentNullException($"{viewName} does not match any available view");
}
var viewDictionary =
new ViewDataDictionary(
new EmptyModelMetadataProvider(),
new ModelStateDictionary()) { Model = model };
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
new TempDataDictionary(actionContext.HttpContext, this.tempDataProvider),
sw,
new HtmlHelperOptions());
await viewResult.View.RenderAsync(viewContext);
return sw.ToString();
}
}
}
Un pensamiento importante aquí: si usa la compilación de vistas (compilaciones previas a YourProject.Web.PrecompiledViews.dll
), entonces es importante obtener la vista usando el método GetView
lugar de FindView
. Más información here .
Genera el archivo PDF desde HTML usando PhantomJS
Para esta tarea vamos a utilizar un navegador sin cabeza que representará el HTML (con todos los CSS y JS incluidos en él). Existen muchas herramientas de este tipo, pero PhantomJS (WebKit sin PhantomJS con una API de JavaScript). PhantomJS puede guardar la página renderizada en PDF de tamaño pequeño bastante rápido. Para que la exportación de PDF funcione, necesitaremos un archivo .js
que usará la API de PhantomJS para indicar a la herramienta que queremos exportar el archivo:
"use strict";
var page = require(''webpage'').create(),
system = require(''system''),
address,
output;
console.log(''Usage: rasterize.js [URL] [filename] [paperformat]'');
address = system.args[1];
output = system.args[2];
page.viewportSize = { width: 600, height: 600 };
page.paperSize = { format: system.args[3], orientation: ''portrait'', margin: ''0.5cm'' };
page.open(address, function (status) {
if (status !== ''success'') {
console.log(''Unable to load the address!'');
phantom.exit(1);
} else {
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});
Lo siguiente es ejecutar el proceso phantomjs.exe
y pasar el archivo rasterize.js
junto con las rutas para el archivo HTML y el nombre del archivo de salida para el resultado de PDF. Esto se hace en HtmlToPdfConverter.cs
:
public interface IHtmlToPdfConverter
{
byte[] Convert(string htmlCode);
}
public class HtmlToPdfConverter : IHtmlToPdfConverter
{
public byte[] Convert(string htmlCode)
{
var inputFileName = "input.html";
var outputFileName = "output.pdf";
File.WriteAllText(inputFileName, htmlCode);
var startInfo = new ProcessStartInfo("phantomjs.exe")
{
WorkingDirectory = Environment.CurrentDirectory,
Arguments = string.Format(
"rasterize.js /"{0}/" {1} /"A4/"",
inputFileName,
outputFileName),
UseShellExecute = true,
};
var process = new Process { StartInfo = startInfo };
process.Start();
process.WaitForExit();
var bytes = File.ReadAllBytes(outputFileName);
File.Delete(inputFileName);
File.Delete(outputFileName);
return bytes;
}
}
Si va a implementar su aplicación en Azure, es importante que UseShellExecute
esté configurado en true
.
Usa el código juntos
Como ahora hemos implementado tanto IViewRenderService
como IHtmlToPdfConverter
, podemos comenzar a usarlos primero registrándolos en el archivo Startup.cs
, donde debe ubicarse su método ConfigureServices ( services.AddScoped<IViewRenderService, ViewRenderService>()
services.AddScoped<IHtmlToPdfConverter, HtmlToPdfConverter>()
). Ahora veamos el código envuelto juntos:
private readonly IViewRenderService viewRenderService;
private readonly IHtmlToPdfConverter htmlToPdfConverter;
public DashboardController(
IViewRenderService viewRenderService,
IHtmlToPdfConverter htmlToPdfConverter)
{
this.viewRenderService = viewRenderService;
this.htmlToPdfConverter = htmlToPdfConverter;
}
[HttpGet]
public async Task<IActionResult> GetPdf(SomeInputModel input)
{
var model = this.GetViewModel(input);
var htmlData = await this.viewRenderService.RenderToStringAsync("~/Views/Dashboard/GetPdf.cshtml", model);
var fileContents = this.htmlToPdfConverter.Convert(htmlData);
return this.File(fileContents, "application/pdf");
}
Este es un ejemplo completo para MVC Razor en C # usando evo html to pdf para .net para convertir la vista actual de MVC a PDF y enviar el PDF resultante al navegador para descargarlo:
[HttpPost]
public ActionResult ConvertCurrentPageToPdf(FormCollection collection)
{
object model = null;
ViewDataDictionary viewData = new ViewDataDictionary(model);
// The string writer where to render the HTML code of the view
StringWriter stringWriter = new StringWriter();
// Render the Index view in a HTML string
ViewEngineResult viewResult = ViewEngines.Engines.FindView(ControllerContext, "Index", null);
ViewContext viewContext = new ViewContext(
ControllerContext,
viewResult.View,
viewData,
new TempDataDictionary(),
stringWriter
);
viewResult.View.Render(viewContext, stringWriter);
// Get the view HTML string
string htmlToConvert = stringWriter.ToString();
// Get the base URL
String currentPageUrl = this.ControllerContext.HttpContext.Request.Url.AbsoluteUri;
String baseUrl = currentPageUrl.Substring(0, currentPageUrl.Length - "Convert_Current_Page/ConvertCurrentPageToPdf".Length);
// Create a HTML to PDF converter object with default settings
HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter();
// Convert the HTML string to a PDF document in a memory buffer
byte[] outPdfBuffer = htmlToPdfConverter.ConvertHtml(htmlToConvert, baseUrl);
// Send the PDF file to browser
FileResult fileResult = new FileContentResult(outPdfBuffer, "application/pdf");
fileResult.FileDownloadName = "Convert_Current_Page.pdf";
return fileResult;
}
Esto es cómo hacerlo usando MVC
:
[Route("ABCDD")]
[HttpGet]
public void ABCDD() {
WebClient wc = new WebClient();
// string url = HttpContext.Current.Request.Url.AbsoluteUri;
string url = "http://localhost:3042/Reports/COAListing";
string fileContent = wc.DownloadString(url);
List<string> tableContents = GetContents(fileContent, table_pattern);
string HTMLString = String.Join(" ", tableContents.ToArray());
Document pdfDoc = new Document(PageSize.A4, 10f, 10f, 10f, 0f);
PdfWriter.GetInstance(pdfDoc, HttpContext.Current.Response.OutputStream);
pdfDoc.Open();
pdfDoc.Add(new Paragraph("Welcome to dotnetfox"));
List<IElement> htmlarraylist = HTMLWorker.ParseToList(new StringReader(HTMLString), null);
for (int k = 0; k < htmlarraylist.Count; k++) {
pdfDoc.Add((IElement) htmlarraylist[k]);
}
pdfDoc.Close();
HttpContext.Current.Response.ContentType = "pdf/application";
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;" +
"filename=sample.pdf");
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Write(pdfDoc);
HttpContext.Current.Response.End();
}
Hay un step-by-step tutorial
detallado y step-by-step tutorial
sobre CodeProject que puede seguir. Ilustra cómo puede servir una Vista MVC de ASP.NET como archivo PDF utilizando iTextSharp para la conversión. No obstante, tenga en cuenta que iTextSharp no fue diseñado para convertir HTML a PDF, por lo que es posible que no pueda manejar muy bien las páginas HTML complejas y los estilos CSS.
Una buena forma de convertir de MVC HTML View a PDF (incluso si no está directamente en el tema con respecto a iTextSharp) es usar Rotativa :
Install-Package Rotativa
Esto se basa en wkhtmltopdf
pero tiene mejor soporte de css que el que tiene iTextSharp y es muy sencillo de integrar con MVC, ya que simplemente puede devolver la vista como pdf:
public ActionResult GetPdf()
{
//...
return new ViewAsPdf(model);// and you are done!
}
public virtual void printpdf(string html)
{
String htmlText = html.ToString();
Document document = new Document();
string filePath = HostingEnvironment.MapPath("~/Content/Pdf/");
PdfWriter.GetInstance(document, new FileStream(filePath + "//pdf-"+Filename+".pdf", FileMode.Create));
document.Open();
iTextSharp.text.html.simpleparser.HTMLWorker hw = new iTextSharp.text.html.simpleparser.HTMLWorker(document);
hw.Parse(new StringReader(htmlText));
document.Close();
}
simplemente pase la html string
al parámetro de la cadena que obtendrá por el text = viewname....
parcial de vista parcial text = viewname....