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

Conoscere la versione di SQL Server

by andrea 02 August 2007 23:08

Questa me la devo proprio segnare perchè so già che mi tornerà presto utile.smile_wink
Per conoscere la versione di SQL Server installata è sufficiente eseguire questa Query:

SELECT  @@version, 
        SERVERPROPERTY('productversion'), 
        SERVERPROPERTY ('productlevel'), 
        SERVERPROPERTY ('edition')

e otterete dei dati simili ai seguenti:

Version: Microsoft SQL Server 2005 - 9.00.2050.00 (Intel X86)   Feb 13 2007 23:02:48   Copyright (c) 1988-2005 Microsoft Corporation  Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)
ProductVersion: 9.00.2050.00
ProductLevel: SP1
Edition: Standard Edition

Fonte: How to identify your SQL Server version and edition

Technorati tags:

Tags:

Reporting Services | SQL Server

Reporting Services 2005, da dove cominciare

by Andrea 02 August 2007 22:08

Dovete/volete iniziare a conoscere SQL Server 2005 Reporting Services ma non sapete da dove cominciare?

Un buon inizio sono i Books Online, che potete trovare a questo link:
SQL Server 2005 Books Online - Reporting Services

Cavoli….mi senbra quasi uno slogan commerciale smile_teeth

Tags:

Reporting Services

Disegnare i report a seconda del rendering

by Andrea 28 May 2007 20:05

Quando dovete creare un Report di Reporting Services, dovete considerare (e stare attenti) al tipo di rendering che vorrete utilizzare. Questo perchè a seconda del rendering che sceglierete ci saranno delle differenze nel layout dei vostri report.

Il non averlo saputo prima, mi è costato un bagno di sangue per il semplice fatto che mi sono dovuto ripassare i Report già creati per risitemare e adattare il tutto.

Una cosa non banale, ad esempio, è che nel rendering HTML, non è previsto la sovrapposizione di item nel Report, ma ci sono molte altre differenze. Ecco quelle che riguardano il rendering HTML

  • The HTML rendering extension builds a table in HTML to contain each set of report items. Items are positioned in the table to preserve the report layout.
  • Locations and sizes are expressed in millimeters (mm). Differences of less than .2 mm are rendered as 0 mm.
  • HTML does not support item overlap. This can result in layout changes as the report is displayed.
  • A subreport is rendered as a DIV tag in the HTML report.


In rete ho trovato un documento che ne spiega alcune di queste differenze, ed inoltre, contiene alcuni tips parecchio utili:

  • Using Rectangles to Keep Objects Together
  • Avoiding Blank Pages
  • Using Page Breaks to Improve Performance for Large Reports
  • Using Filters Instead of Query Parameters
  • Adding Alternating Bars to a Table
  • Inserting A Page Break Following A Specific Number of Rows in A Table
  • Adding Global Values to Headers and Footers
  • Displaying Report Items in the Page Header
  • Creating Drill-Down Links with Conditional Formatting

Il documento è scaricabile da qui Best Practices and Guidelines (.doc) e vi consiglio vivamente la lettura perchè sono sicuro potrà farvi risparmiare parecchio tempo anche a voi. 

Fonte: Report Design: Best Practices and Guidelines

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