Unisciti a 4 altri iscritti
Itek Developer
Programmare è arte
Generare un pdf in asp.net con iTextSharp
18 agosto 2011
Pubblicato da su 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.
- Download del codice ( asp.net – c# – Framework 3.5 ) : pdfAndAspnet35.zip
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 :
- 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 :
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.
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 :
C’è qualcuno che ancora risponde a questo post?
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
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);
}
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
come si fa ad aprire il pdf in una nuova pagina browser?? grazie in anticipo
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!
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à 😉
Non conosco bene il vb.net e non intendo approfondire perché non mi piace 🙂
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
Cosa intendi per delimitato ? Vuoi aprire il pdf in una nuova pagina del browser ?