web-dev-qa-db-fra.com

Comment rendre une vue ASP.NET MVC au format PDF

Je travaille avec l'utilitaire de conversion HTML vers PDF d'ExpertPDF pour cette question (bien que je sois ouvert à d'autres bibliothèques s'il y a une documentation suffisante).

En bref, j'ai une vue qui est formatée d'une manière spécifique et je voudrais la rendre comme un document PDF que l'utilisateur peut enregistrer sur le disque.

Ce que j'ai jusqu'à présent est un PrintService (qui implémente une interface IPrintService) et cette implémentation a deux surcharges pour PrintToPDF (), une qui ne prend qu'une URL et une autre qui prend une chaîne HTML, et qui renvoient toutes les deux un octet []. Je n'ai travaillé que sur les détails de la deuxième surcharge qui nécessite la chaîne HTML.

Ce que je voudrais faire de mon contrôleur est quelque chose comme:

public FileStreamResult Print(int id)
{
    var model = _CustomRepository.Get(id);
    string renderedView = SomethingThatRendersMyViewAsAString(model);
    Stream byteStream = _PrintService.PrintToPdf(renderedView);
    HttpContext.Response.AddHeader("content-disposition", 
        "attachment; filename=report.pdf");
    return new FileStreamResult(byteStream, "application/pdf");  
}

qui en théorie donnerait un PDF à la page. C'est le "SomethingThatRendersMyViewAsAString" avec lequel je cherche de l'aide. Existe-t-il un moyen rapide d'obtenir la représentation sous forme de chaîne d'une vue? Ou peut-être Je devrais juste m'en tenir à la surcharge d'URL et passer une URL à la vue ... D'autres réflexions?

Merci!

24
nkirkes

Vous pourrez peut-être puiser dans la réponse pendant OnResultExecuting et remplacer la propriété Filter par quelque chose qui stocke le code HTML résultant dans un MemoryStream. Ensuite, vous pouvez effacer la réponse pendant OnResultExecuted et la remplacer par les résultats de votre conversion PDF. Je ne suis pas sûr que ce serait mieux que de simplement obtenir le code HTML à partir de l'URL, cependant.

 public FileStreamResult Print(int id)
 {
     var model = _CustomRepository.Get(id);
     this.ConvertToPDF = true;
     return View( "HtmlView" );
 }

 public override OnResultExecuting( ResultExecutingContext context )
 {
      if (this.ConvertToPDF)
      {
          this.PDFStream = new MemoryStream();
          context.HttpContext.Response.Filter = new PDFStreamFilter( this.PDFStream );
      }
 }

 public override OnResultExecuted( ResultExecutedContext context )
 {
      if (this.ConvertToPDF)
      {
          context.HttpContext.Response.Clear();
          this.PDFStream.Seek( 0, SeekOrigin.Begin );
          Stream byteStream = _PrintService.PrintToPDF( this.PDFStream );
          StreamReader reader = new StreamReader( byteStream );
          context.HttpContext.Response.AddHeader( "content-disposition",
                 "attachment; filename=report.pdf" );
          context.HttpContext.Response.AddHeader( "content-type",
                 "application/pdf" );
          context.HttpContext.Response.Write( reader.ReadToEnd() );
      }
}

Le PDFStreamFilter devrait remplacer la ou les méthodes "Write" et envoyer les données au flux mémoire à la place.

10
tvanfosson

J'ai emballé ma solution dans un package Nuget: Rotativa http://nuget.org/packages/Rotativa . Il est basé sur wkhtmltopdf.

L'utilisation est vraiment simple.

Ayant une action que vous souhaitez servir de Pdf, au lieu de la page Html. Vous pouvez définir une action qui renvoie un ActionResult du type ActionAsPdf (RouteAsPdf est également disponible). Le code est donc juste:

public ActionResult PrintIndex()
{
    return new ActionAsPdf("Index", new { name = "Giorgio" }) { FileName = "Test.pdf" };
}

Le nom = "Giorgio" étant un paramètre d'itinéraire.

Cela fonctionne même si l'action à imprimer est protégée par l'authentification par formulaire Web (attribut [Authorize])

98
Giorgio Bozio

Cela ressemble à un problème similaire que j'ai rencontré lorsque je voulais utiliser Views comme modèles de courrier électronique. La meilleure réponse que j'ai trouvée pour obtenir la représentation sous forme de chaîne d'une vue était ici: rendre une vue sous forme de chaîne

1
Jason

Le meilleur package que j'ai trouvé est le RazorPDF , disponible sous forme de package sur NuGet.org, basé sur iTextSharp . Fonctionne sur les sites Web Azure:

https://nuget.org/packages/RazorPDF

0