J'essaie de convertir HTML en PDF avec iTextSharp
dans MVC Razor, mais tout ce que j'ai essayé n'a pas fonctionné. Est ce que quelqu'un sait comment accomplir cela?
Il y a un code détaillé et step-by-step tutorial
sur CodeProject que vous pourriez suivre. Il illustre comment vous pouvez servir une vue ASP.NET MVC en tant que fichier PDF à l'aide de iTextSharp pour la conversion. N'oubliez pas cependant qu'iTextSharp n'est pas destiné à la conversion de HTML en PDF, de sorte qu'il risque de ne pas très bien gérer les pages HTML complexes et les styles CSS.
Voici comment vous implémentez cette solution en utilisant le Razor engine NOT avec le balisage bizarre <itext..
.
De cette façon, vous avez un contrôle total sur la présentation pdf en utilisant une sortie HTML standard.
Le projet avec un exemple de solution et de code source est disponible ici avec les instructions d’installation de nuget:
https://github.com/andyhutch77/MvcRazorToPdf
Install-Package MvcRazorToPdf
Ceci utilise également la nouvelle licence itextsharp, ne souffre donc d'aucun des inconvénients mentionnés dans les autres réponses.
Vous devriez vérifier RazorPDF qui utilise iText pour générer le PDF, mais de manière plus conviviale.
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();
}
il suffit de passer html string
au paramètre cette chaîne que vous obtiendrez par renderpartialview text = viewname....
Voici un exemple complet pour MVC Razor en C # utilisant le evo html en pdf pour .net pour convertir la vue MVC actuelle en PDF et envoyer le résultat PDF au navigateur pour téléchargement:
[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;
}
Un bon moyen de convertir MVC HTML View vers PDF (même si ce n'est pas directement sur le sujet concernant iTextSharp) utilise Rotativa :
Install-Package Rotativa
Ceci est basé sur wkhtmltopdf
mais il offre un meilleur support CSS que iTextSharp et est très simple à intégrer à MVC car vous pouvez simplement retourner la vue au format pdf
public ActionResult GetPdf()
{
//...
return new ViewAsPdf(model);// and you are done!
}
Si vous utilisez ASP.NET Core et que iTextSharp n’est pas si important pour vous, voici ma solution utilisant PhantomJS: http://nikolay.it/Blog/2018/03/Generate-PDF-file-from-Razor- view-using-ASP-NET-Core-and-PhantomJS/37
Cette étape est assez simple. Il existe un service appelé IRazorViewEngine
dans ASP.NET Core qui peut être injecté puis utilisé pour obtenir la vue. Après avoir fourni la vue avec les valeurs par défaut ViewDataDictionary
et ActionContext
, nous pouvons demander que la vue soit rendue en StringWriter
qui peut être facilement convertie en chaîne. Voici du code prêt à l'emploi pour obtenir une chaîne à partir d'un fichier de vue Razor donné:
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();
}
}
}
Une chose importante à penser ici: si vous utilisez la compilation de vues (précompiler des vues avec YourProject.Web.PrecompiledViews.dll
), il est important d’obtenir la vue en utilisant la méthode GetView
au lieu de FindView
. Plus d'informations ici .
Pour cette tâche, nous allons utiliser un navigateur sans interface graphique qui restituera le code HTML (avec tous les fichiers CSS et JS inclus). Il existe de nombreux outils de ce type, mais je vais utiliser PhantomJS (WebKit sans tête, scriptable avec une API JavaScript). PhantomJS peut enregistrer la page rendue au format PDF de petite taille assez rapidement. Pour que l’exportation PDF fonctionne, nous aurons besoin d’un fichier .js
qui utilisera l’API PhantomJS pour indiquer à l’outil que nous souhaitons exporter le fichier:
"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);
}
});
La prochaine étape consiste à exécuter le processus phantomjs.exe
et à transmettre le fichier rasterize.js
ainsi que les chemins d'accès au fichier HTML et le nom du fichier de sortie pour le résultat PDF. Ceci est fait dans 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 vous souhaitez déployer votre application dans Azure, il est important que UseShellExecute
soit défini sur true
.
Puisque nous avons maintenant implémenté IViewRenderService
et IHtmlToPdfConverter
, nous pouvons commencer à les utiliser en les enregistrant d’abord dans le fichier Startup.cs
où votre méthode ConfigureServices doit être située (services.AddScoped<IViewRenderService, ViewRenderService>()
et services.AddScoped<IHtmlToPdfConverter, HtmlToPdfConverter>()
). Voyons maintenant le code encapsulé ensemble:
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");
}
Voici comment faire en utilisant 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();
}
ici, vous pouvez trouver une approche différente dans le cas où vous voudriez écrire du XML simple, je le trouve beaucoup plus simple et plus léger.
http://www.codeproject.com/Articles/260470/PDF-reporting-using-ASP-NET-MVC3