Per quanto ci si impegni a farcire il nostro software di report statistiche, estrazioni dati, analisi aggregate, è matematico che a un certo punto salta sempre fuori il rompiscatole (ehm... volevo dire l'esperto) di turno che ci farà la solita lanconica richiesta: avere un'estrazione automatica di alcuni dati.
Ovviamente detta analisi deve avvenire periodicamente e inviare il risultato finale via excel, per poter eseguire poi delle post-elaborazioni.
Siccome questa statistica è importantississimissssssssssssssima deve giungere tassativamente entro la mattina, e pertanto l'elaborazione deve avvenire la notte precedente.
Sono certo che chi fa il lavoro di (tentativo di) programmatore si sarà sentito rivolgere questa richiesta centinaia di volte, magari con declinazioni e variazioni varie, ma con la medesima sostanza.
Siccome il cliente committente ha sempre ragione, sopratutto se paga, occorre trovare il modo di soddisfare detta richiesta.
Il primo problema classico che occorre risolvere è che generalmente sul server dove deve avvenire l'elaborazione NON è installato office, per cui non possiamo usare l'office automation (Microsft Office Object Library).
Attenzione: Esiste un'ampia letteratura in merito. Installare office o altri software desktop-centrici sul server è cattiva prassi, e deve essere evitato.
Pertanto non ci si può rivolgere a office: come fare ?!
Esistono alcune soluzioni.
1) Creare il file in formato csv, che può essere importato da excel e per la cui generazione non è necessario alcun ausilio particolare.
2) Usare una qualche libreria per creare file excel o formati compatibili che non necessitino della presenza di excel.
3) Convincere il cliente che non ha bisogno di alcun estrazione.
Per quanto rigaurda il punto 1 a volte può essere difficoltoso convincere il cliente circa l'utilizzo del formato csv: infatti a volte l'importazione in execl può non essere precisa e sopratutto chi non è molto "avezzo l'utilizzo degli strumenti informatici" può avere delle difficoltà.
La soluzione al punto 3 è impraticabile molte volte, anche solo per una questione di orgoglio personale !
Rimane la soluzione esposta al punto 2: ma cosa usare ?
Io ho provato e utilizzato ottenuto buoni risultati utilizzando la libreria ClosedXML, e pertanto ho pensato di scriverne alcune note.
Come recita il sito "ClosedXML rende facile per gli sviluppatori creare file in formato Excel 2007+ (.xlsx, .xlsm, etc). La libreria fornisce gli strumenti object-oriented per manipolare tale tipi di file, e può essere usato in qualsiasi linguaggio .NET come C# e Visual Basic (VB.Net).
Oss.: Per meglio specificare i file generati da ClosedXML NON sono in formato xls, bensì formato xlsx, che è il nuovo formato perfettamente supportato da excel e che rappresenta un'evoluzione del formato dei fogli di calcolo.
La libreria è anche disponibile via NuGet, per cui approfittatene !
PM> Install-Package ClosedXML
Nel seguito un piccolo pezzo di codice che permette di creare un semplice file.
using ClosedXML.Excel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace InfPressExcel { class Program { static void Main(string[] args) { var workbook = new XLWorkbook(); var worksheetInLavorazione = workbook.Worksheets.Add("Sheet01"); worksheetInLavorazione.Cell("A1").SetValue <string>("Titolo in posizione A1"); worksheetInLavorazione.Cell("Z1").SetValue<string>("Cella Posizione Z1"); workbook.SaveAs(@"F:\test.xlsx"); workbook.Dispose(); } } }
Dopo aver creato il XLWorkBook (che sarebbe il file) si aggiunge a questo un WorkSheet (cioè un foglio di calcolo).
Fatto questo abbiamo inserito un valore nella cella A1 e in Z1: interessante il fatto che il setvalue sia generics, e così facendo la cella accoglierà nel modo adatto il dato inserito (automagicametne la cella sarà con datatype corretto).
Nel seguito un altro snippet, che permette di inserire un pò di righe senza doversi riferire con lettera/numero (battaglia navale style per capirsi...).
var workbook = new XLWorkbook(); var worksheetInLavorazione = workbook.Worksheets.Add("Sheet01"); IXLRow rowForNewData = worksheetInLavorazione.FirstRow(); rowForNewData.Cell(1).SetValue("Titolo Foglio");
worksheetInLavorazione.Range(1, 1, 1, 2).Merge();
worksheetInLavorazione.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; IXLRows righe = worksheetInLavorazione.LastRowUsed().InsertRowsBelow(10); foreach (var item in righe) { item.Cell(1).SetValue(item.RowNumber().ToString()); item.Cell(2).SetValue(item.RowNumber() * 10); } workbook.SaveAs(@"F:\test.xlsx"); workbook.Dispose();
Usando il codice sopra si ottiene il risultato in figura.
Il codice è esplicativo: prima occorre creare le righe (InsertRowsBelow) e quindi popolarle. Si è anche eseguito il merge della cella che contiene il titolo, ponendo quindi il testo al centro.
La libreria permette di creare fogli molto complessi, con formule e immagini, e quindi la gerarchia degli oggetti è abbastanza complessa, anche se ritengo sia ben progettata e abbastanza intuitiva una volta compresi i principi generali.
Vi rimando al sito e alla documentazione lì contenuta.
Linkografia