Reporting Services - creazione di uno snapshot

by Andrea 25 February 2010 08:46

Come scritto nel post precedente, stò dando all'utente finale la possibilità di gestirsi gli snapshot direttamente dall'applicazione, ed ora tocca alla fase di creazione di uno snapshot.

Come ben sapete (e come ho scritto in questo post) gli snapshot vengono creati utilizzando i valori di default dei parametri.
Reporting Services fornisce la possibilità di forzare la creazione di uno snapshot tramite il metodo CreateReportHistorySnapshot, che si comporta esattamente come il pulsante presente nel sito di sharepoint di Reporting, che crea lo snapshot utilizzando i valori dei parametri in quel preciso istante (quindi facendo uso dei valori di default).

Ma se volessimo eseguire uno snapshot che abbia diversi parametri?
E' il caso in cui il report abbia le date o dei filtri calcolati in automatico, magari perchè deve venire eseguito con i dati della settimana precedente, o del mese precedente. Però Il cliente potrebbe avere la necessità di rigenerare il report riferito ad un perioso diverso (magari di 2 settimane prima).
In questo caso si può intervenire andando a modificare da codice i valori di default dei parametri del report, e dopo aver eseguito lo snapshot, ripristinarli ai valori normali.

Ecco qui il codice da qui potete prendere spunto:

   1: using (ReportingService2005SoapClient rs = this.CreateReportingService2005SoapClient())
   2: {
   3:     string batchID = string.Empty;
   4:     ServerInfoHeader infoHeader = rs.CreateBatch(out batchID);
   5:     BatchHeader bh = new BatchHeader()
   6:     {
   7:         BatchID = batchID,
   8:         AnyAttr = infoHeader.AnyAttr
   9:     };
  10:     CatalogItem[] items = null;
  11:     rs.ListChildren(reportFolder, true, out items);
  12:  
  13:     foreach (var item in items)
  14:         if (string.Compare(item.ID, reportId.ToString(), true) == 0)
  15:         {
  16:             // recupero gli attuali parametri e mi tengo una copia degli originali
  17:             ReportParameter[] defaultParameters = null;
  18:             ReportParameter[] parameters = null;
  19:             rs.GetReportParameters(item.Path, null, false, null, null, out defaultParameters);
  20:             rs.GetReportParameters(item.Path, null, false, null, null, out parameters);
  21:  
  22:  
  23:             foreach (ReportParameter parameter in parameters)
  24:             {
  25:                 //modifico i valori dei parametri che voglio cambiare
  26:                 if (string.Compare(parameter.Name, "dateStart", true) == 0)
  27:                     parameter.DefaultValues = new string[] { string.Format("{0:s}", startDate) };
  28:                 else if (string.Compare(parameter.Name, "dateEnd", true) == 0)
  29:                     parameter.DefaultValues = new string[] { string.Format("{0:s}", endDate) };
  30:             }
  31:             // setto i parametri modificati nel report
  32:             rs.SetReportParameters(bh, item.Path, parameters);
  33:             string historyId = string.Empty;
  34:             Warning[] warnings = null;
  35:             // creo lo snapshot
  36:             rs.CreateReportHistorySnapshot(bh, item.Path, out historyId, out warnings);
  37:             // setto i parametri originali
  38:             rs.SetReportParameters(bh, item.Path, defaultParameters);
  39:             // eseguo il tutto sotto un'unica transazione
  40:             rs.ExecuteBatch(bh);
  41:             return;
  42:         }
  43: }

Faccio notare che il tutto viene eseuito sotto un'unica transazione al comando rs.ExecuteBatch(bh), e in caso di errori, il report continuerebbe ad avere i suoi normali valori di default e non i valori da noi modificati.

Technorati Tags: ,

Tags:

SQL Server | Reporting Services | .NET

Reporting Services - cancellare uno snapshot da codice

by Andrea 24 February 2010 03:49

Può capitare di voler dare la possibilità all'utente di cancellare uno snapshot di un determinato report, e dargli la possibilità di farlo direttamente dall'applicazione che abbiamo realizzato.

Oggi mi sono scontrato con questa problematica, e uscirne non è stato proprio immediato a causa della scarsa documentazione a riguardo. Spero quindi che questo post sia utili a qualcuno.

Nella classe ReportingService2005SoapClient (del proxy generato verso il WebService di Reporting Services) esiste un metodo DeleteReportHistorySnapshot che si occupa per l'appunto di cancellare un preciso snapshot (DeleteReportHistorySnapshot), ma il come utilizzarlo è stato un pò oscuro.

Ecco qui il codice finale, che recupera il path del report, conoscendone l'id (scorrendo i report contenuti in una precisa cartella), e successivamente richiama la cancellazione dello snapshot avente l'historyId conosciuto.

   1: using (ReportingService2005SoapClient rs = this.CreateReportingService2005SoapClient())
   2: {                
   3:     string batchID = string.Empty;
   4:     ServerInfoHeader infoHeader = rs.CreateBatch(out batchID);
   5:     BatchHeader bh = new BatchHeader()
   6:     {
   7:         BatchID = batchID,
   8:         AnyAttr = infoHeader.AnyAttr
   9:     };
  10:  
  11:     CatalogItem[] items = null;
  12:     rs.ListChildren(reportFolder, true, out items);
  13:  
  14:     foreach (var item in items)
  15:         if (string.Compare(item.ID, reportId.ToString(), true) == 0)
  16:         {
  17:             rs.DeleteReportHistorySnapshot(bh, item.Path, historyId);
  18:             rs.ExecuteBatch(bh);
  19:         }
  20: }

La difficoltà è stata nel capire cosa fosse il BachHeader, e il di dover chiamare rs.ExecuteBatch,  che si occupa di lanciare i comandi che sono stati inviati utilizzando lo stesso BatchHeader sotto un'unica transazione. Non avendo mai fatto uso (in passato) di metodi a cui viene passato un oggetto BatchHeader, questa soluzione non mi è venuta proprio spontanea.

Ecco un link a riguardo delle operazioni eseguite in batch in reporting services: Batching Methods

Tags:

SQL Server | Reporting Services | .NET

Reporting Services - report snapshots

by andrea 23 July 2009 02:31

Una funzionalità che trovo molto utilie di Reporting Services sono gli Report Snapshots.

Cos'è un report snapshot?

Uno Report Snapshot non è altro che una copia del report, eseguito in un preciso istante. Questa copia conterrà tutte le informazioni necessarie per permettere di visualizzare il report in un secondo momento, e avere lo stato al momento della sua creazione.

Quando viene chiesto di salavare uno snapshots, Reporting Services esegue il report in questione e immagazzina tutte le informazioni che vanno a popolare i dataset utilizzati nel report stesso (e anche il layout del report). In questo modo, quando viene richiesta la visualizzazione di un preciso Snapshot, si hanno a disposizione i dati già elaborati, che erano presenti in quel preciso istante (data + ora).
Ecco cosa viene salvato nel server di Reporting Services:

  • The result set (that is, the data in the report, retrieved through the credentials specified in the Data Sources properties page of the report).
  • The underlying report definition, as it exists at the time the snapshot was created. If the report definition was subsequently modified after the snapshot was generated, those changes are not reflected in the snapshot.
  • Parameter values that are used to obtain or filter the result set.
  • Embedded resources, such as images. External resources that are linked to a report are not stored with the report snapshot.

Un enorme vantaggio, che porta all'uso dei Report Snapshots, è il fatto di poter essere schedulati, ed esistono molte impostazioni possibili a riguardo. (esecuzione a intervalli prestabiliti, in precisi giorni, una sola volta, ...)

I Report Snapshots hanno però anche delle limitazioni, una di queste, è dovuta al fatto che vengono salvanti anche i valori dei parametri, e questo comporta che se vogliamo Snapshot con parametri differenti, si dovranno creare differenti Report (o Linked Reports), ma questo è anche capibile.
In alcune condizioni però, è possibile utilizzare un parametro (visibile) all'interno del report per filtrare i dati. Infatti, il filtro dei dati all'interno del report è una prassi consentita, in quanto viene applicato ai dati che popolano i DataSet (e quindi immagazzinati nello snapshot)

Quando utilizzare i report snapshots?

Possono essere utilizzati prevalentemente per due motivazioni:

  • Si vuole avere uno storico di un determinato report.
    Schedulando la creazione di snapshot a determinati intervalli, permettono di avere esattamente la situazione (il risultato del report) in quel dato momento, e quindi poter eseguire a posteriore una visualizzazione di tali dati.
  • Esecuzione di report che richiedono molto tempo di elaborazione.
    E' possibile schedulare l'esecuzione di snapshot per ovviare al problema dell'attesa per l'elaborazione di report che richiedono un lungo tempo di caricamento. In questo modo, l'utente può visualizzare l'ultimo snapshot eseguito, che verrà caricato velocemente in quanto i dataset sono già stati popolati durante la creazione dello snapshot, risparmiando così l'attesa all'utente.

Come visualizzare uno snapshot nel controllo ReportViewer

Per visualizzare uno snapshot di un preciso report nel controllo ReportViewer è sufficiente impostare la proprietà HistoryId del controllo, con l'ID dello snapshot che si vuole visualizzare.

reportViewer.ServerReport.HistoryId = historyID;

Utilizzando il web service esposto da Reporting Services (Consumare il web service di Reporting Services) è possibile recuperare la lista di Snapshots di un determinato report, e utilizzare i dati ricevuti per recuperare l'identificativo dell'ultimo Snapshot eseguito.
Ecco come poter recuperare la lista di tutti gli snapshot di un determinato report:

   1: public ReportHistorySnapshot[] GetReportHistory(string reportFullPath)
   2: {
   3:   using (ReportingService2005SoapClient rs = ReportingService2005SoapClient())
   4:   {
   5:       rs.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
   6:       rs.ClientCredentials.Windows.ClientCredential.UserName = "username";
   7:       rs.ClientCredentials.Windows.ClientCredential.Password = "password";      
   8:  
   9:       ReportHistorySnapshot[] snapshots = null;
  10:       rs.ListReportHistory(reportFullPath, out snapshots);
  11:  
  12:       return snapshots;
  13:   }
  14: }

Link:

Tags: ,

SQL Server | .NET | Reporting Services

Consumare il web service di Reporting Services

by andrea 16 July 2009 08:05

Ecco come utilizzare il web service di Reporting Services (utilizzando basicHttpBinding)
(sia per Reporting Services 2005 che per Reporting Services 2008)

Per poter utilizzare il (uno dei) web service esposto da Reporting Serives, si dovrà creare una Service Reference facendola puntare all'url
http://127.0.0.1/reportserver/ReportService2005.asmx?wsdl
dove 127.0.0.1 sarà l'IP della macchina dove è installato Reporting Services.

Aggiunta la referenza, verrà automaticamente generata la configurazione all'interno dell'app.config, e nell'elemento basicHttpBinding saranno da modificare:

  • in binding --> security: modificare l'attributo mode in TransportCredentialOnly
  • in binding --> security --> transport: impostare clientCredentialType e proxyCredentialType a Ntlm

La configurazione finale sarà quindi la seguente:

   1: <system.serviceModel>
   2:     <bindings>
   3:         <basicHttpBinding>
   4:             <binding name="ReportingService2005Soap" closeTimeout="00:01:00"
   5:                 openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
   6:                 allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
   7:                 maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
   8:                 messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
   9:                 useDefaultWebProxy="true">
  10:                 <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
  11:                     maxBytesPerRead="4096" maxNameTableCharCount="16384" />
  12:                 <security mode="TransportCredentialOnly">
  13:                     <transport clientCredentialType="Ntlm" proxyCredentialType="Ntlm"
  14:                         realm="" />
  15:                     <message clientCredentialType="UserName" algorithmSuite="Default" />
  16:                 </security>
  17:             </binding>
  18:         </basicHttpBinding>
  19:         <customBinding>
  20:             <binding name="ReportingService2005Soap12">
  21:                 <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
  22:                     messageVersion="Soap12" writeEncoding="utf-8">
  23:                     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
  24:                         maxBytesPerRead="4096" maxNameTableCharCount="16384" />
  25:                 </textMessageEncoding>
  26:                 <httpTransport manualAddressing="false" maxBufferPoolSize="524288"
  27:                     maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Ntlm"
  28:                     bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
  29:                     keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Ntlm"
  30:                     realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
  31:                     useDefaultWebProxy="true" />
  32:             </binding>
  33:         </customBinding>
  34:     </bindings>
  35:     <client>
  36:         <endpoint address="http://127.0.0.1:80/ReportServer/ReportService2005.asmx"
  37:             binding="basicHttpBinding" bindingConfiguration="ReportingService2005Soap"
  38:             contract="ReportingServices.ReportingService2005Soap" name="ReportingService2005Soap" />
  39:     </client>
  40: </system.serviceModel>

Ora, per poter invocare i metodi del web service è necessario impersonare un utente della macchina di Reporting Services (che abbia i diritti correttamente impostati), andando a settare i valori nelle rispettive proprietà della classe ClientCredentials.

Impersonato l'utente, sarà poi possibile invocare i metodi esposti dal servizio.

   1: using (ReportingService2005SoapClient rs = new ReportingService2005SoapClient())
   2: {
   3:     rs.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
   4:     rs.ClientCredentials.Windows.ClientCredential.UserName = "username";
   5:     rs.ClientCredentials.Windows.ClientCredential.Password = "password";
   6:     rs.ClientCredentials.Windows.ClientCredential.Domain = "domain";    
   7:  
   8:     CatalogItem[] items = null;
   9:     rs.ListChildren("/", true, out items);
  10:     // [...]
  11: }

Alcune ulteriori informazioni le potete trovare al seguente link:
Reporting Services Web Service

Per un progetto a cui stò lavorando, ho dovuto fare uno studio per alcune funzionalità che dovevano pesantemente interagire con il web service di Reporting Services.
Ho notato che le informazioni in rete sono un pò sparse e frazionate, e quindi mi è sembrato utile scrivere due righe per aiutare chi fosse ai primi passi (su questa problematica).

Tags:

ASP .NET | .NET | SQL Server | Reporting Services

Conversione Local Report a Server Report e viceversa

by Andrea 03 September 2007 21:09

Visto che non è la prima volta che lo cerco, segnalo un link utile a chi deve convertire un report da RDLC a RDL e anche convertire un report da RDL a RDLC:

link: Converting RDL and RDLC Files

Technorati tags: , ,

Tags:

Reporting Services

Reporting Services e field che collassano

by Andrea 28 May 2007 20:05

A volte può essere un problema che le TextBox nei report callassino quando i field non hanno valore.
Una semplice soluzione a questo problema è quella di aggiungere uno spazio in coda al valore dei field:

=Fields!Description.Value

un'altra strada può essere quella di sostituire il valore empty ottenuto dal field con uno spazio:

=IIF(Fields!Description. = "", " ", Fields!Description.Value)

<update del 30.05.2007>
oppure (semplicemente) settare la proprietà InitialToggleState al valore Expanded. (Che di default invece è Collapsed)
</update>

A volte è proprio vero, la strada più semplice è anche la migliore!

Technorati tags: ,

Tags: ,

Reporting Services

Reporting Services e bug su field empty

by Andrea 14 May 2007 12:05

Ebbene si, avete letto bene, mi sono trovato davanti ad un bug di Reporting Services che secondo me è davvero grave. Il problema si presenta quando usate una fonte dati xml, e uno dei field del primo elemento non ha valore (es <modello />). Se inserite il field in una lista, noterete che per tutta la colonna non verrà mai valorizzato, mentre, il tutto funziona correttamente se a non aver valore è un field che non sia nel primo elemento.

Se volete riprodurre l'errore, non dovete fare altro che usare come fonte dati un xml tipo questo (e lo impostate come sorgente dati nel report):

<?xml version="1.0" ?>
<automobili>
<auto><marca>fiat</marca><modello /></auto>
<auto><marca>fiat</marca><modello>punto</modello></auto>
</automobili> 

e come query scrivete:

<Query>
<ElementPath IgnoreNamespaces="true">
automobili/auto
</ElementPath>
</Query> 

Noterete che nel dataset non esisterà la colonna "modello", e questo perchè l'elemento "modello" (che è presente) nel xml non è valorizzato.

Ponendo il problema anche nei newsgroup Microsoft di SQL Server, vengo a sapere che sono a conoscenza del problema, e che per il momento non non c'è nessuna soluzione.
L'unica cosa che potete fare è intervenire nel file xml e fare in modo che tutti i campi siano valorizzati. Workaround non sempre praticabile e sicuramente non elegante, ma è l'unica strada percorribile per il momento.

Inutile provare con =Fields!modello.IsMissing o cose del genere perchè perdereste solo tempo, come è capitato a me. Quindi non ci resta che sperare che il bug venga corretto al più presto.

Technorati tags: , , ,

Tags: ,

Reporting Services

[Reporting Services] Pubblicare un'applicazione che usa ReportViewer

by Andrea 12 September 2006 13:09

Se dovete pubblicare un'applicazione che fa uso del componente ReportViewer per visualizzare i vostri report, ricordatevi che nel server dovrete installare ReportViewer.exe, che trovate al seguente link http://www.microsoft.com/downloads/details.aspx?familyid=8a166cac-758d-45c8-b637-dd7726e61367&displaylang=en .

Per maggiori informazioni ed esempi sull'uso di questo componente vi consiglio di visitare questo sito:
http://www.gotreportviewer.com/

Tags: , ,

.NET | Reporting Services

[Reporting Services] ReportViewer non stampa i LocalReport

by Andrea 06 September 2006 18:09

 

L'ultima sorpresa a riguardo dei LocalReport mi ha davvero spiazzato...se state usando ReportViewer per visualizzare i LocalReport non avrete la possibilità di utilizzare il classico bottoncino di stampa che di solito popola la toolbar.

Questa proprio non me l'aspettavo. Ma perchè non le scrivono a caratteri cubitali queste cose?! E su MSDN a questo link questo piccolo dettaglio  (_piccolo_ in senso ironico)  non stà scritto.

Vabbè. Comunque il motivo è che con i report in locale il ReportViewer non è in grado di creare i file EMF che servono per lo  lo spool di stampa.

Ora mi toccherà passare i report già creati sul server di ReportingServices, e per fortuna non ci sono chissà che modifiche da compiere.

Tags: , ,

Reporting Services

[Reporting Services] Prelevare un valore da un controllo contenuto nel Report

by Andrea 04 September 2006 14:09

Nei nostri Report ci può tornare utile avere la possibilità di prelevare il valore di un dato contenuto in un'altra controllo , come ad esempio il testo contenuto in una TextBox posizionata nella pagina.

La sintassi è la seguente:
=ReportItems!textbox1.Value

Questo ci può tornare utile nel caso volessimo eseguire operazione e/o funzioni usando dati contenuti in più celle.

Tags: ,

.NET | Reporting Services