Stampa in automatico

venerdì 03 ottobre 2008 - 10.47

Pokino Profilo | Junior Member

Ciao di nuovo, ecco la 2' grana di oggi

Sto lavorando ad un gestore di report per le statistiche 'aziendali', ora il capo mi ha chiesto di verificare se è possibile stampare tutti i report con un unico comando piuttosto che doverli aprire uno per uno e avviare manualmente la procedura. In effetti visto che sono una 20ina sarebbe molto comodo ma qualcuno ha idea di come fare?

Grazie

freeteo Profilo | Guru

ciao,
diciamo che un comando predisposto a questa operazione non c'è, però puoi provare a farlo via codice.
Io farei un caricamento da codice del report, passaggio dati se necessario o cmq settaggio dei parametri di connessione, e poi lanciare l'esportazione in pdf.
Poi tramite iTextSharp (http://itextsharp.sourceforge.net/ in questa pagina trovi anche dei tutorial) oppure tramite GhostScript, fare il merge di questi in un'unico file pdf.
A questo punto li hai fatti diventare uno solo, il processo presuppone 1po di codice e il test del caso, ma è fattibile a mio avviso.

Se questa strada è percorribile, risentiamoci che ti do maggiori dettagli sul codice da scrivere.


ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Pokino Profilo | Junior Member

ciao, nn mi è arrivata la mail di notifica della risposta e ho iniziato a scrivere del codice selfmade..

// stampa tutti i report disponibili protected void btnStampaTutto_Click(object sender, EventArgs e) { // carica i report SqlConnection connessione = new SqlConnection(connDb); connessione.Open(); string sqlCmd = [..]; //selezione del nome file dei report SqlCommand comando = new SqlCommand(sqlCmd, connessione); SqlDataReader reader; reader = comando.ExecuteReader(); // crea l'istanza del report ReportDocument myRepStampa = new ReportDocument(); string NomeFile = ""; string path = ""; try { while (reader.Read()) { NomeFile = reader.GetString(0); path = Request.PhysicalApplicationPath + "reports\\" + NomeFile; // stampa myRepStampa.Load(path); myRepStampa.SetDatabaseLogon([..], [..]); myRepStampa.PrintToPrinter(1, false, 0, 0); } myRepStampa.Close(); } catch (Exception ex) { LblMessaggi.Text = "Attenzione: " + ex.Message ; LblMessaggi.Visible = true; } reader.Close(); connessione.Close(); }

e con mio grande sollievo funziona ma ahimè solo in localhost in fase di sviluppo!
quando pubblico sul server e premo il pulsante la pagina macina macina ma nn arriva mai e nn succede nulla....

quale potrebbe essere il motivo?

ps: ho pensato alla mancanza di una stampante sul server, ma io nn specifico il nome della stampante accontentandomi di quella di default, e sul server non vedo processi in coda.

freeteo Profilo | Guru

>quando pubblico sul server e premo il pulsante la pagina macina
>macina ma nn arriva mai e nn succede nulla....
bisognerebbe capire se il report viene caricato correttaemnte e poi si blocca in fase di stampa, o se ci sono problemi al caricamento...cmq sia supponiamo che il report si carichi correttamente (cosa che potresti provare con un viewer prima di stamparlo)


>ps: ho pensato alla mancanza di una stampante sul server, ma
>io nn specifico il nome della stampante accontentandomi di quella
>di default, e sul server non vedo processi in coda.
si potrebbe essere allora relativo al fatto che il processo non ha diritti di stampare, cosa che è anche corretta perchè tu stai facendo una stampa su un server con l'utente con cui gira l'applicazione o sei in esecuzione su un computer locale?
ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Pokino Profilo | Junior Member

uso Crystal Reports..

sono in esecuzione locale..

qui: http://aspalliance.com/509_Automatically_Printing_Crystal_Reports_in_ASPNET.2

ho visto che le stampanti devono essere visibili dal server.. cavolaccio..

freeteo Profilo | Guru

>uso Crystal Reports..
>sono in esecuzione locale..
quindi hai un'applicazione Windowsfrom che gira sul pc dell'utente?
Perdonami ma non ho ancora capito se il tuo report lo stai visualizzando su un pc locale con un exe, o se hai una pagina web che gira su browser...


>qui: http://aspalliance.com/509_Automatically_Printing_Crystal_Reports_in_ASPNET.2
>ho visto che le stampanti devono essere visibili dal server..
si diciamo che nel pc dove sta girando l'exe (o nel caso di applcazione web, il webserver) devono essere raggiungibili quelle stampanti che ti servono, perchè non fa altro che fare la stessa cosa che farebbe un'utente per stampare un file qualsiasi, solo che lo fa da codice impostando la stampante per nome (senza quindi dialogo di stampa) ma il processo è lo stesso che fai da Windows.


ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Pokino Profilo | Junior Member

sto sviluppando in asp.net una applicazione web

il comando printtoprinter farebbe al caso mio perchè mi evita, volendo stampare 20 report, di aprire n finestre di stampa.. però sono in una situazione particolare perchè ho degli utenti che lavorano nella stessa rete del server e penso di riuscire a preparare qualcosa che permetta di far loro selezionare la stampante del server (anche se io in locale non seleziono nulla, nn impostando nulla da codice mi prende quella di default del mio server cioè della mia macchina), ma molti altri utenti lavorano su reti diverse

freeteo Profilo | Guru

>sto sviluppando in asp.net una applicazione web
ok allora non sei in "esecuzione locale" ma sei in "esecuzione su server"


>nn impostando nulla da codice mi prende quella di default del
>mio server cioè della mia macchina), ma molti altri utenti lavorano
>su reti diverse
certo, solitamente è proprio così, il fatto di stampare lato server non ha molto senso nel 99% dei casi.

Quello che puoi fare è usare la stessa tecnica per fare un pdf dei vari report, unirlo tramite ItextSharp (usando quindi questa libreria e scrivendo del codice tutto sommato abbastanza semplice) o GhostScript (da riga di comando passando i parametri giusti).
Dopo che hai creato un'unico file, lo dai in pasto come risposta all'utente nel suo browser, a questo punto l'utente avrà sicuramente un reader per Pdf come Acrobat (o FoxitReader), e deciderà lui su che stampante stamparlo.
Un passaggio in più, ma necessario a fare le cose "fatte bene"

ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Pokino Profilo | Junior Member

>
>certo, solitamente è proprio così, il fatto di stampare lato
>server non ha molto senso nel 99% dei casi.
>
>Quello che puoi fare è usare la stessa tecnica per fare un pdf
>dei vari report, unirlo tramite ItextSharp (usando quindi questa
>libreria e scrivendo del codice tutto sommato abbastanza semplice)
>o GhostScript (da riga di comando passando i parametri giusti).
>Dopo che hai creato un'unico file, lo dai in pasto come risposta
>all'utente nel suo browser, a questo punto l'utente avrà sicuramente
>un reader per Pdf come Acrobat (o FoxitReader), e deciderà lui
>su che stampante stamparlo.
>Un passaggio in più, ma necessario a fare le cose "fatte bene"
>

beh, visto che è stata implementata una istruzione (printtoprinter) ho cercato di capire come usarla al meglio, anche perchè permette di risolvere alla grande specifiche situazioni, forse però troppo specifiche.. in realtà avrei trovato una strada, infatti rendendo visibile al server la stampante del mio ufficio (con l'unico inconveniente di impostare a everyone i permessi altrimenti iis non riesce ad accedervi.. grana da risolvere) e passando il nome della stampante con

myRepStampa.PrintOptions.PrinterName =

sono riuscito! a questo punto si potrebbe risolvere brillantemente il problema quantomeno nella rete interna, memorizzando nel profilo utente la stampante da utilizzare ed ovviamente aggiungendola al server dove gira iis


tuttavia sono interessato anche ad esplorare le altre strade, quella che suggerisci tu e un'altra idea che potrebbe essere altrettanto valida: creare al volo un report vuoto e inserirvi come sottoreport tutti quelli che voglio stampare, poi stampare il report padre.. che dici?

freeteo Profilo | Guru

>altrettanto valida: creare al volo un report vuoto e inserirvi
>come sottoreport tutti quelli che voglio stampare, poi stampare
>il report padre.. che dici?
attento che da codice non riesci a farlo, non con la licenza di visual studio per lo meno, perchè non è possibile fare report da zero via codice.
Potresti fare un report con i sottoreport si, ma deve essere fatto a design e poi eventualmente riempito via codice, e poi stampato/esportato...


ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Pokino Profilo | Junior Member

ho iniziato ad esplorare itextsharp e con un po' di fortuna ho trovato un codice vb che fa il merge di 2 file in un nuovo file, l'ho riscritto in c# e leggerissimamente modificato e funziona, anche se ha una magagna sulla creazione dei segnalibri (una chicca ma utile, devo fare delle prove ancora)

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

ora i problema è come prendere in input i report di crystal e generare in output un pdf da aprire nel browser invece che salvarlo su filesystem del server..

freeteo Profilo | Guru

>ora i problema è come prendere in input i report di crystal e
>generare in output un pdf da aprire nel browser invece che salvarlo
>su filesystem del server..
si Crystal lavora con l'export su disco, o su byte in memoria (metodo "ExportToStream") ma cmq sono file già completi, non sono le "singole parti" che puoi assemblare come vuoi, sono proprio i Bytes che salvati su disco puoi rinominare in ".pdf" ed aprirli per intenderci.

Quindi vedi se riesci con ITextSharp a lavorare con lo stream meglio, altrimenti parcheggialo su un file temporaneo, magari te lo fai dare dalla classe "Path" del Namespace "System.IO" con il metodo Path.GetTempFileName() e poi caricarlo da quello, e poi quando hai il pdf, lo cancelli.

ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Pokino Profilo | Junior Member

mi piacerebbe evitare di scrivere prima i file dei singoli report.. l'istruzione iTextSharp.text.pdf.PdfReader() accetta come parametro uno stream quindi sto tentando

// dato myReport caricato..

1 Stream s = Stream.Null;
2 s = myReport.ExportToStream(ExportFormatType.PortableDocFormat);
3 iTextSharp.text.pdf.PdfReader reader = null;
4 reader = new iTextSharp.text.pdf.PdfReader(s);

viene però generata eccezione in 4 (impossibile accedere a un flusso chiuso) e se metto un break in 3
e guardo s lo stesso messaggio viene presentato in s.Length mentre la variabile interna _length è correttamente valorizzata..

qual'è il mio errore madornale?


freeteo Profilo | Guru

ciao,
io proverei con questo codice:
MemoryStream ms = report.ExportToStream(ExportFormatType.PortableDocFormat) as MemoryStream; PdfReader reader = new PdfReader(ms.ToArray()); ...

ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Pokino Profilo | Junior Member

grazie, nn mi da più errore e da n report posso generare ora un unico file .pdf..

devo ancora vedere di farlo scaricare al client.. è possibile evitare di scriverlo sul server secondo te e redirigerlo direttamente al browser?

questione probabilmente più critica: poichè devo elaborare n report la cosa potrebbe essere decisamente lunga come tempo e devo evitare:
- che il tutto si pianti per timeout
- che si veda un avanzamento lavori
- che l'utente non possa lavorare nel frattempo

come posso lavorare in tal senso? riesco a lanciare un thread separato?

freeteo Profilo | Guru

>grazie, nn mi da più errore e da n report posso generare ora
>un unico file .pdf..
ok perfetto!


>devo ancora vedere di farlo scaricare al client.. è possibile
>evitare di scriverlo sul server secondo te e redirigerlo direttamente
>al browser?
eh certo quando hai il pdf in formato "array di bytes" puoi fare:
Response.ContentType = "application/octet-stream"; Response.AddHeader("Content-Disposition", "attachment; filename=" + nome); Response.OutputStream.Write(bytePDF, 0, bytePDF.Lenght);
dove "bytePDF" è un byte[] fatto dal documento o il reader di ItextSharp...guarda se l'oggetto che hai, invece di salvarlo su file, ti permette di averlo come byte[]...



>questione probabilmente più critica: poichè devo elaborare n
>- che il tutto si pianti per timeout
>- che si veda un avanzamento lavori
"avanzamento" direi proprio di no, puoi usando Ajax, in particolare un "UpdatePanel" con dentro il bottone che fa la richiesta "lato-server", e un "UpdateProgress" fare cmq una piccola gif di animazione (magari poi con css la posizioni al centro della pagina) e l'utente sa che qualcosa sta ancora caricando...ma un "step-by-step" dei vari passaggi quello non lo saprei proprio fare.


>- che l'utente non possa lavorare nel frattempo
cosa intendi qui? se segui il suggerimento di ajax sopra, puoi mettere la pagina in un link "target=_blank" in modo che l'altra pagina sotto rimanga libera...diciamo che in qualche modo ce la fai a lasciare che non sia l'unica finestra di explorer aperta e che debba restare li ad aspettare, ma è più che altro una questione di html (di un pop-up)


>come posso lavorare in tal senso? riesco a lanciare un thread
>separato?
ogni richiesta dal client (browser->pagina asp.net in IIS) è sempre in un thread separato, dato che HTML è un protocollo passivo, e questo spiega la mancanza di "stato" come può essere un'applicazione Win32, infatti devi lavorare con Session,Application etc...cose che diciamo si arrangiano il framework e IIS a mantenere per te, tra i vari thread.


ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo

Pokino Profilo | Junior Member

>eh certo quando hai il pdf in formato "array di bytes" puoi fare:
>
> Response.ContentType = "application/octet-stream";
>Response.AddHeader("Content-Disposition", "attachment; filename="
>+ nome);
>Response.OutputStream.Write(bytePDF, 0, bytePDF.Lenght);
>dove "bytePDF" è un byte[] fatto dal documento o il reader di
>ItextSharp...guarda se l'oggetto che hai, invece di salvarlo
>su file, ti permette di averlo come byte[]...

grazie 1000, ora posso scrivere o su file o inviare al client il pdf

per il resto probabilmente dovrò usare una popup per svincolare l'utente da questo lavoro di generazione / stampa, a meno
di non velocizzare alla grande la cosa, magari appoggiandosi alla cache? in questo caso nn so come fare..

devo provare anche con Ajax ma in questo caso se usassi una sola finestra l'utente rimarrebbe bloccato giusto?

freeteo Profilo | Guru

>grazie 1000, ora posso scrivere o su file o inviare al client
>il pdf
di niente, se la risposta è stata utile accettala che chiudiamo il thread.


>per il resto probabilmente dovrò usare una popup per svincolare
>l'utente da questo lavoro di generazione / stampa, a meno
esatto, come ti dicevo metti magari un pulsante, e sull'onClientClick metti una funzione che ti apra il popup


>di non velocizzare alla grande la cosa, magari appoggiandosi
>alla cache? in questo caso nn so come fare..
non saprei nemmeno io come fare in questo caso, perchè i report devono essere generati in quel determinato momento.
Se vuoi avere una cache, puoi usare la Session...ma attento che appesantisci, vedi tu come vai meglio.


>devo provare anche con Ajax ma in questo caso se usassi una sola
>finestra l'utente rimarrebbe bloccato giusto?
mah direi di no perchè ajax (con updatepanel) poi va ad impegnare solo la singola parte che deve fare l'update (ecco perchè dovresti avere più updatepanel) solo che l'utente può cmq sempre cliccare ingiro, e farti morire il thread che lato server in realtà è già partito, e sprechi elaborazione per niente.
Io ti consiglierei di restare sulla strada del popup, è quello che ti risulta più facile.

ciao.

Matteo Raumer
[MCAD .net]
http://blogs.dotnethell.it/freeteo
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5