Itek Developer

Programmare è arte

Generare un pdf in asp.net con iTextSharp

Come saprete asp.net non supporta nativamente le classi necessarie per generare  un file pdf.  Per ottemperare a questa mancanza , alcuni sviluppatori di terze parti hanno creato delle librerie apposite.  Tra le tante , c’è la libreria iTextSharp , una libreria totalmente gratuita che offre ottime prestazioni ed è di facile utilizzo sia per quanto riguarda l’installazione ( occorre soltanto inserire nel  progetto una dll ) sia per quanto riguarda la programmazione.  Potete scaricare la libreria a questo indirizzo  .

Di seguito ho messo a disposizione il link per scaricare l’esempio che andremo ad analizzare. Se decidete di scaricare il codice di esempio , potrete evitare di scaricare la libreria in quanto essa è già contenuta nel progetto.

L’Esempio e il codice :

La prima cosa da fare è ovviamente quella di creare una nuova applicazione vuota asp.net con Visual Studio. Una volta creato il progetto , nella cartella del  progetto stesso , inserite nella cartella “bin” il file iTextSharp.dll .  Aggiungete al progetto un Reference alla libreria come fareste per una qualsiasi altra dll.  Ed è tutto , ora siamo pronti per generare il pdf.

Nell’esempio proposto andremo a prelevare i dati da un database MSSQL che contiene i dati di un’ipotetica lista dei monumenti più belli del Mondo ( ovviamente il db è molto semplificato in quanto lo scopo di questo tutorial non è quello di dimostrare le pontenzialità di MSSQL).  Di seguito riporto la struttura della tabella places del db places.mdf :

click image to enlarge

Struttura della tabella places da cui andremo a prelevare i dati

  • id = chiava primaria univoca
  • autore = autore dell’articolo
  • titolo = titolo dell’articolo
  • descrizione = descrizione dell’articolo
  • link = link che fa riferimento all’immagine per l’articolo
  • lat = latitudine della località
  • lng = longitudine della località
Per questo esempio lasceremo ad un valore predefinito ( zero ) i campi lat e lng.
Le immagini da visualizzare sono contenute in una cartella di nome “immagini” . Di seguito riporto la struttura del progetto da Solution Explorer di Visual Studio :
click image to enlarge
Struttura del progetto
Nell’immagine potete notare la cartella DBLogic al cui interno abbiamo il file DBPlacesLogic.cs. All’interno di esso troviamo due classi :
  • places
  • DBPlacesLogic
La prima servirà per mappare esattamente la struttura della tabella places e che utilizzeremo come struttura per contenere i dati recuperati dal db.
La classe DBPlacesLogic contiene tutte le funzioni necessarie per l’inizializzazione e il dialogo con il db.
Di seguito riporto il codice delle due classi
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;

namespace pdfAndAspnet.DBLogic
{

    /* ----------------------------------------- */
    /* Classe places che mappa la tabella del DB */
    /* ----------------------------------------- */

    public class places
    {
        public int      id          { get; set; }
        public string   autore      { get; set; }
        public string   titolo      { get; set; }
        public string   descrizione { get; set; }
        public string   link        { get; set; }
        public float    lat         { get; set; }
        public float    lng         { get; set; }

        // Costruttore vuoto
        public places() { }

        // Costruttore parametrizzato
        public places(int _id, string _titolo, string _descrizione, string _link, float _lat, float _lng)
        {
            this.id             = _id;
            this.titolo         = _titolo;
            this.descrizione    = _descrizione;
            this.link           = _link;
            this.lat            = _lat;
            this.lng            = _lng;
        }
    }

    /* ----------------------------------- */
    /* Classe per l'interfacciamento al DB */
    /* ----------------------------------- */

    public class DBPlacesLogic
    {

        string connString   = string.Empty;
        SqlConnection conn  = new SqlConnection();

        //Recupera tutti i records dal database e restituisce una lista di oggetti palces
        //che verrà usata per popolare il DataGrid nella pagina principale ( Default.aspx )
        public List<places> GetAllPlaces()
        {
            List<places> tempPlaces = new List<places>();

            InitDBLogic();
            string sqlQueryString = "SELECT * FROM places";
            SqlCommand sqlCmd = new SqlCommand(sqlQueryString, conn);
            sqlCmd.CommandType = CommandType.Text;
            SqlDataReader sqlReader = sqlCmd.ExecuteReader();

            while (sqlReader.Read())
            {
                places result = new places();
                result.id = (int)sqlReader["id"];
                result.autore = (string)sqlReader["autore"];
                result.titolo = (string)sqlReader["titolo"];
                result.descrizione = (string)sqlReader["descrizione"];
                result.link = (string)sqlReader["link"];
                result.lat = Convert.ToSingle(sqlReader["lat"]);
                result.lng = Convert.ToSingle(sqlReader["lng"]);
                tempPlaces.Add(result);
            }
            sqlReader.Close();
            conn.Close();
            return tempPlaces;
        }

        // Dato uno specifico id recupera  il record dal database e restituisce un oggetto places
        public places GetPlaceByID(int id)
        {
            InitDBLogic();
            string sqlQueryString = "SELECT * FROM places WHERE id='" + id.ToString() + "'";
            SqlCommand sqlCmd = new SqlCommand(sqlQueryString , conn);
            sqlCmd.CommandType = CommandType.Text;
            SqlDataReader sqlReader = sqlCmd.ExecuteReader();
            places result = new places();
            while (sqlReader.Read())
            {
                result.id = (int) sqlReader["id"];
                result.autore = (string) sqlReader["autore"];
                result.titolo = (string) sqlReader["titolo"];
                result.descrizione = (string) sqlReader["descrizione"];
                result.link = (string) sqlReader["link"];
                result.lat = Convert.ToSingle(sqlReader["lat"]);
                result.lng = Convert.ToSingle(sqlReader["lng"]);
            }
            sqlReader.Close();
            conn.Close();
            return result;
        }

        // Recupera la ConnectionString dal web.config e inizializza la connessione al database
        private void InitDBLogic()
        {
            connString = ConfigurationManager.ConnectionStrings["placesConnectionString"].ToString();
            conn.ConnectionString = connString;
            conn.Open();
        }

    }
}
Non staremo a spiegare come accedere ed utilizzare un database MSSQL in quanto non è lo scopo di questo tutorial. Andiamo invece a vedere meglio la parte che riguarda la libreria iTexSharp e la creazione del pdf. Come vedete dalla struttura del progetto ( immagine in alto ) abbiamo due pagine aspx :
  • Default.aspx
  • GeneraPdf.aspx
Nella prima , che è la home page del nostro sito , verrà visualizzata una GridView  con tutti i record presenti nel nostro db. Ad essa ho aggiunto una colonna per il “select” di none “Genera il PDF”. Quindi per ogni record avremo la possibilità di selezionare il record. Selezionando uno specifico record , verrà generata una chiamata alla pagina GeneraPdf.aspx con un parametro di nome id. In sostanza facciamo una chiamata alla pagina GeneraPdf.aspx con il supporto di una query string con il solo parametro id che rappresenta il campo id del record selezionato nella GridView.
click image to enlarge

Screenshot della GridView nella pagina Default.aspx

Vediamo il code behind per la pagina Default.aspx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.IO;
using pdfAndAspnet.DBLogic;

namespace pdfAndAspnet
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            DBPlacesLogic dbLogic = new DBPlacesLogic();
            DBGridView.DataSource = dbLogic.GetAllPlaces();
            DBGridView.DataBind();
        }

        protected void DBGridView_SelectedIndexChanged(object sender, EventArgs e)
        {
            string queryParameter = DBGridView.Rows[DBGridView.SelectedIndex].Cells[1].Text;
            string queryString = "~/GeneraPdf.aspx?id=" + queryParameter;
            Response.Redirect(queryString);
        }

    }
}
Appena avviate l’applicazione viene caricata la pagina Default.aspx che a sua volta richiamerà l’evento Page_Load. Come potete vedere, all’interno della funzione che intercetta tale evento , creiamo un oggetto di tipo DBPlacesLogic di nome dbLogic che ci permetterà di accedere al db. A questo punto richiamiamo la funzione GetAllPlaces() che ci restituisce tutti i records presenti nel db in una lista di oggetti places che assegniamo come datasource per la nostra GriedView per poi essere visualizzata come mostrato in figura. Quando andremo a selezionare un record , premendo sul link select “Genera il PDF” , viene generato l’evento SelectedIndexChanged. Tale evento viene intercettato dalla funzione DBGridView_SelectedIndexChanged(). All’interno di essa inseriamo nella variabile queryParameter il valore del campo “id” del record selezionato , creiamo la query string alla pagina GeneraPdf.aspx inserendo come parametro id proprio il valore di id memorizzato nella variabile queryParameter. A questo punto, con Response.Redirect(queryString), richiamiamo  la pagina che genererà il nostro pdf.

GeneraPdf.aspx

Ed eccoci finalmente alla parte saliente , la generazione del pdf :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using pdfAndAspnet.DBLogic;

namespace pdfAndAspnet
{
    public partial class GeneraPdf : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

            // Istanza dell'oggetto DBPlacesLogic per il recupero dei dati dal database
            DBPlacesLogic dbLogic = new DBPlacesLogic();
            // Recuperiamo i dati dal db andando a caricare nell'oggetto queryResult i dati
            // del record con id uguale al parametro id nella query string
            places queryResult = dbLogic.GetPlaceByID(Convert.ToInt32(Request.QueryString["id"]));

            string id = queryResult.id.ToString();
            string autore = queryResult.autore;
            string titolo = queryResult.titolo;
            string descrizione = queryResult.descrizione;
            string link = queryResult.link;

            // Creiamo il documento PDF istanziando l'oggetto Document messo a disposzione
            // dalla libreria iTextSharp
            var document = new Document(PageSize.A4, 100, 100, 25, 25);

            // Creiamo un oggetto MemoryStream che conterrà in memoria il file pdf che andremo
            // via via creando con i passi successivi
            var output = new MemoryStream();
            var writer = PdfWriter.GetInstance(document, output);

            // Aprimao il docmento
            document.Open();

            // Creiamo i vari fonts che utilizzeremo nel nostro pdf
            //( per maggiori dettagli: http://www.mikesdotnetting.com/Article/81/iTextSharp-Working-with-Fonts )
            var titleFont = FontFactory.GetFont("Arial", 20, Font.BOLD);
            var subTitleFont = FontFactory.GetFont("Arial", 14, Font.BOLD);
            var boldTableFont = FontFactory.GetFont("Arial", 12, Font.BOLD);
            var endingMessageFont = FontFactory.GetFont("Arial", 10, Font.ITALIC);
            var bodyFont = FontFactory.GetFont("Arial", 12, Font.NORMAL);

            // Aggiungiamo un paragrafo per la visualizzazione del titolo
            document.Add(new Paragraph("World Places", titleFont));
            // Aggiungiamo un ulteriroe paragafro per il sottotitolo
            document.Add(new Paragraph("Foto e Info dei più belli monumenti del Mondo", bodyFont));
            // Aggiungiamo una linea vuota e andiamo a capo
            document.Add(Chunk.NEWLINE);

            // Aggiungiamo un paragrafo che contiene il titolo della risorsa
            string strInfo = "Informazioni riassuntive su : " + titolo;
            document.Add(new Paragraph(strInfo, subTitleFont));

            // Creiamo una tabella per visualizzare le informazioni recuperate dal database
            //( Per maggiori info su come creare una tabela con iTextSharp : http://www.mikesdotnetting.com/Article/86/iTextSharp-Introducing-Tables )
            var infoTable = new PdfPTable(2);
            infoTable.HorizontalAlignment = 0;
            infoTable.SpacingBefore = 10;
            infoTable.SpacingAfter = 10;
            infoTable.DefaultCell.Border = 0;

            infoTable.SetWidths(new int[] { 2, 4 });
            infoTable.AddCell(new Phrase("Id:", boldTableFont));
            infoTable.AddCell(id);
            infoTable.AddCell(new Phrase("Autore:", boldTableFont));
            infoTable.AddCell(autore);
            infoTable.AddCell(new Phrase("Descrizione:", boldTableFont));
            infoTable.AddCell(descrizione);
            infoTable.AddCell(new Phrase("Link:", boldTableFont));
            infoTable.AddCell(link);
            document.Add(infoTable);

            // Creiamo un ogetto immagine iTextSharp
            var logo = iTextSharp.text.Image.GetInstance(System.Web.HttpContext.Current.Server.MapPath(link));
            // Definiamo le propietà dell'immagine
            logo.ScaleToFit(150f, 150f);
            logo.Alignment = iTextSharp.text.Image.ALIGN_LEFT;
            logo.IndentationLeft = 9f;
            logo.SpacingAfter = 9f;
            logo.Border = Rectangle.BOX;
            logo.BorderColor = Color.BLACK;
            logo.BorderWidth = 5f;
            document.Add(logo);

            // Aggiungiamo due linee vuote
            document.Add(Chunk.NEWLINE);
            document.Add(Chunk.NEWLINE);

            // Aggiungiamo un paragrafo per il messaggio di chiusura
            var endingMessage = new Paragraph("Questo PDF è stato generato grazie all'utilizzo della libreria iTextSharp", endingMessageFont);
            endingMessage.SetAlignment("Center");
            document.Add(endingMessage);

            // Chiudiamo il documento PDF
            document.Close();

            // Settiamo l'http header in modo che la risposta del server sia del tipo pdf
            // ( passaggio fondamentale )
            Response.ContentType = "application/pdf";
            // Ed infine mandiamo in output il nostro stream che contiene appunto i dati del nostro pdf
            Response.BinaryWrite(output.GetBuffer());
        }
    }
}
Per poter utilizzare la libreria iTextSharp all’interno di una pagina aspx occorre prima di tutto inserire le direttive
  • using iTextSharp.text;
  • using iTextSharp.text.pdf;
Quando viene fatta la richiesta alla pagina GeneraPdf.aspx , per prima cosa viene eseguito il metodo Page_Load(). Ed è all’interno di esso che creiamo il nostro pdf. Per iniziare creiamo un oggetto di tipo DBPlacesLogic per accedere al db ( riga 21 del codice ).  Alla riga 24 , creiamo un oggetto di tipo places che conterrà i dati del record che ha come id il valore fornito dalla query string che avevamo precedentemente creato nella pagina Default.aspx quando selezioniamo un record dalla GridView : GetPlaceByID(Convert.ToInt32(Request.QueryString[“id”])).
Il resto dei commenti che trovate nel  codice qui sopra vi spiega il resto dei passaggi.
Ecco uno screenshot del pdf creato dal nostro codice :

Screenshot del pdf creato con iTextSharp

10 risposte a “Generare un pdf in asp.net con iTextSharp

  1. emanuele 22 luglio 2014 alle 14:32

    C’è qualcuno che ancora risponde a questo post?

  2. Aldo 27 gennaio 2014 alle 11:20

    Salve. Come faccio a salvare fisicamente il file pdf generato. In questo modo viene creato in memoria ma se lo volessi salvare sul server? Grazie

    • Web Master 1 febbraio 2014 alle 00:18

      Subito dopo la chiusura del pdf document ( riga 104 del codice) aggiungi il seguente
      codice : dovrebbe funzionare 🙂

      using (FileStream file = new FileStream(“tuoNomeFile.pdf”, FileMode.Create, FileAccess.Write)) {
      output.WriteTo(file);
      }

    • FGL11 18 aprile 2014 alle 01:21

      Ho provato a fare una piccola parte del tuo codice

      Document document = new Document(PageSize.A4, 100, 100, 25, 25);
      MemoryStream output = new MemoryStream();
      PdfWriter writer = PdfWriter.GetInstance(document, output);

      document.Open();
      document.NewPage();
      document.Add(Chunk.NEWLINE);
      document.Add(new Paragraph(“PROVA PRAGAGRAFO 1”));
      document.Close();

      using (FileStream file = new FileStream(“tuoNomeFile.pdf”, FileMode.Create, FileAccess.Write))
      {
      output.WriteTo(file);
      }

      Però mi da errore nell’apertura del PDF dicendo che è impossibile accedere ad uno stream chiuso. Come posso risolvere? Grazie per l’eventuale risposta

  3. gio 12 settembre 2012 alle 20:49

    come si fa ad aprire il pdf in una nuova pagina browser?? grazie in anticipo

  4. iMesck 31 luglio 2012 alle 11:40

    Grazie delle info, sono state tanto utili anche per me. Ho una domanda però: mi sono accorta che nel pdf che si genera sulla base delle info che gli passo da db, quando scorrono alla pagina successiva perdono di formattazione e quindi anche se io inserisco ad esempio uno dataTable.SpacingBefore = 50f; non ne tiene conto. Accade nella prima parte della pagina successiva. Come mai? C’è un rimedio…? mi serve per lavoro e sono bloccata…grazie!

  5. spino 26 giugno 2012 alle 00:37

    Finalmente un tutorial che funziona! Ho provato ad integrarlo in un progetto con linguaggio vb anzichè C#, con pessimi risultati. Sarebbe molto bello se esistesse un tutorial anche per quello, che dici, si può fà 😉

  6. giuseppe 12 Maggio 2012 alle 09:06

    Grazie , mi e’ stato molto utile. Ti chiedo , visto che non ho trovato nulla, e’ possibile che il pdf esca non in pagina intera ma delimitato. Io usavo la registrazione del pdf sul server e poi lo lanciavo con Response.Write(“window.open(‘Report/Unimill.pdf’ ,null ,’fullscreen=no, toolbar=no,menubar=no,scrollbars=yes,resizable=yes,width=700px,height=600px’)”)

    Un saluto

Scrivi una risposta a spino Cancella risposta