Magazine

Utilizzare XML nei Local Reports

Davide Senatore

22/01/2007

L'utilizzo di assembly "esterni" in Local Reports può svelare affascinanti possibilità di sviluppo

0%100%
per esprimere un voto è necessario registrarsi al sito

Windows Forms, Reporting

RDLCXML.zip ()

Introduzione

Una delle features più interessanti di Reporting Services, è la possibilità di creare report locali che vengono incorporati nelle nostre applicazioni ed elaborati localmente, senza cioè l'ausilio di un server di reportistica. Questo approccio può essere applicato con estremo profitto in scenari che non richiedano elaborazioni particolari o caching di reports, e che possano demandare al client l'elaborazione dei dati. L'utilizzo più interessante che si può fare di questa tecnologia è però rappresentato dall'impiego di codice custom all'interno del report e dalla possibilità di impiegare assembly esterni, quali System.Data, System.Xml per effettuare elaborazioni durante il rendering del report.

L'applicazione

L'applicazione che andrò a descrivere è veramente molto semplice. Quello che vogliamo ottenere è una lista di documenti, memorizzati in una tabella di un database SQL. Questa tabella ha però una piccola particolarità: il campo Document è di tipo ntext e contiene un documento XML valido, che rappresenta i dati del nostro documento. Attenzione!! Questo è un esempio, e non vuole in alcun modo rappresentare un'alternativa alla maniera (corretta) di memorizzare documenti all'interno di un database, ovvero tramite tabelle in relazione. Ovviamente, il campo XML non può essere rappresentato così com'è e richiederà un'elaborazione dedicata. La tabella dei documenti sarà omunque così composta:

  • Id: uniqueidentifier PK
  • DocumentCode: varchar(10)
  • Document: ntext

L'infrastruttura

Creiamo un'applicazione Windows con una finestra e subito andiamo ad aggiungere il datasource che ci consentirà di caricare i dati dal nostro database. Con il Wizard delle Data Sources andiamo a configurare la connessione al database ed includiamo la tabella Documents nel dataset che verrà creato. Dopo aver fatto questo, sempre impiegando il wizard di Visual Studio, trasciniamo la tabella document contenuta nel Dataset creato sulla Form della nostra applicazione. VS2005 creerà per noi un'istanza del Dataset, un BindingSource relativo alla tabella Documents, un BindingNavigator ed una DataGridView. Per i nostri scopi sono sufficienti il Dataset ed il BindingSource, per cui eliminiamo tutto il resto.

A questo punto inseriamo nella form un CommandButton ed il controllo ReportViewer.Qualora non riusciate a trovarlo nella vostra ToolBox (Scheda Data) lo potete scaricare (royalty -free) da questo sito. Potete trovare maggiori informazioni su metodi e classi utilizzate nell'articolo qui.

Impostiamo l'esecuzione del Report a Local (ProcessingMode=Local) e creiamo un nuovo report. Impostiamolo come report visualizzato dal nostro controllo ReportViewer e impostiamo le datasources, sempre usando l'utilissimo smart-tag di design del controllo ReportViewer. Impostiamo come DataSource il BindingSource relativo alla tabella Documents, creato in precedenza nella form e il gioco è fatto. Nel report creiamo una tabella, trasciniamo i campi DocumentCode e Document nella riga dettaglio della tabella ed il nostro report è pronto per essere renderizzato. Aggiungendo il codice all'evento ButtonClick caricheremo i dati nel dataset ed invocheremo il refresh del nostro report:

Private Sub Button1_Click(ByVal sender As System.ObjectByVal As System.EventArgs) Handles Button1.Click
    
'Carico i dati nel Dataset locale
    
Me.DocumentsTableAdapter.Fill(Me.NorthwindDataSet.Documents)
    
Me.ReportViewer1.RefreshReport()
End Sub

 

 Ci sono però alcune cose da fare prima di arrivare al risultato da noi desiderato.

Report Code

Nel nostro report non possiamo visualizzare il campo documents "così com'è"; è brutto, è XML, è poco chiaro; dobbiamo obbligatoraimente elaborarlo. Una soluzione potrebbe essere rappresentata da un'elaborazione preventiva, ma non è questo lo scopo dell'articolo. Vogliamo elaborare l'XML del campo Documents DIRETTAMENTE dentro al Report. A questo scopo, sostituiamo la proprietà Value della textbox nella griglia con value =Fields!Document.Value con =Code.FormatDocument(Fields!Document.Value).

La Classe code ci permette di salvare del codice, per così dire, "scriptato" direttamente all'interno del Report. Possiamo alimentare tale codice dalla voce "Report Properties" nel menù Report di VS2005. Nel nostro caso, la funzione FormatDocument sarà la seguente:

Public Function FormatDocument(ByVal doc As StringAs String
    Dim 
_doc As New System.Xml.XmlDocument
    _doc.LoadXml(doc)
    
Dim _sb As New System.Text.StringBuilder
    _sb.AppendLine("CustomerId: " & _doc.SelectSingleNode("document/customerId").InnerText)
    _sb.AppendLine("Shipping address: " & _doc.SelectSingleNode("document/address").InnerText)
    _sb.AppendLine("Document value: " & _doc.SelectSingleNode("document/value").InnerText)
    
Return _sb.ToString()
End Function

La funzione accetta in input una stringa e ritorna una stringa. Il funzionamento è volutamente molto semplice, ma sicuramente fa intuire le possibilità offerte da tale approccio. Unico problema? Così com'è non funziona!!!

Assembly Reference e Security Sandbox

Come prima cosa, sempre dalla voce Report Properties, aggiungiamo la referenza all'assembly System.Xml. In questo modo, nel codice potremo referenziare le classi del namespace System.Xml.

Anche così, però, il nostro report non funzionerà, in quanto dovremo impostare il Trusting sull'assembly System.Xml dalla nostra applicazione, tramite il metodo:

Me.ReportViewer1.LocalReport.AddTrustedCodeModuleInCurrentAppDomain("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")

Questa chiamata registra l'assembly specificato per l'utilizzo nell'appdomain corrente, permettendo di fatto l'utilizzo dell'assembly specificato all'interno del report.

L'altra chiamata che dovrà essere obbligatoriamente fatta è:

Me.ReportViewer1.LocalReport.ExecuteReportInCurrentAppDomain(AppDomain.CurrentDomain.Evidence)

In questo modo forziamo il report ad essere eseguito nell' AppDomain corrente e non in un sandboxed AppDomain con privilegi limitati. Questa accortezza ci mette al riparo dall'esecuzione di codice malizioso contenuto nei report. E' necessario passare al metodo l'evidence del CurrentDomain, che raccoglie al suo interno i permessi dell'applicazione "chiamante".

Apportando queste modifiche, il codice del ButtonClick si modifica in questo modo:

 Private Sub Button1_Click(ByVal sender As System.ObjectByVal As System.EventArgs) Handles Button1.Click
    
'Carico i dati nel Dataset locale
    
Me.DocumentsTableAdapter.Fill(Me.NorthwindDataSet.Documents)
    
'Primo step MOLTO IMPORTANTE!
    'Se voglio utilizzare chiamate ad assembly esterni (System.Xml,System.Data...etc) devo impostare
    'l'esecuzione del report nell'App Domain dell'applicazione corrente
    
Me.ReportViewer1.LocalReport.ExecuteReportInCurrentAppDomain(AppDomain.CurrentDomain.Evidence)
    
'Secondo Step
    'Marcare come "trusted" l'assembly al quale vogliamo far riferimento all'interno del codice
    'scritto nel report. Se non si marca l'assembly come trusted, non sarà possibile utilizzarlo nel report.
    
Me.ReportViewer1.LocalReport.AddTrustedCodeModuleInCurrentAppDomain("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    
Me.ReportViewer1.RefreshReport()
End Sub

 

Se il report funzionasse all'interno di un Sandboxed AppDomain, i permessi sarebbero limitati ed il report stesso non potrebbe far riferimento ad assembly esterni, impossibilitando l'esecuzione della nostra funzione FormatDocument.

Conseguenze

Le ricadute di questa tecnologia sono molteplici: potremmo utilizzare una tecnica di questo tipo per:

  • Formattare testo XML;
  • Richiamare funzioni residenti in assembly esterni che generano, ad esempio, immagini;
  • Effettuare sub queries "on demand" all'interno del nostro report, per ottenere dati in tempo reale
  • Invocare Web Services da reports
  • Molto altro...

Conclusioni

I local reports rappresentano una tecnologia molto interessante, spesso sconosciuta alla maggior parte degli sviluppatori. Molte volte si investono parecchie risorse per sviluppare meccanismi "proprietari" per effettuare stampe, oppure si acquistano componenti di terze parti per effettuare report. Visual Studio 2005 rende estremamente semplice l'utilizzo di questa tecnologia e riduce la curva di apprendimento permettendo la creazione di applicazioni report-oriented in pochissimo tempo e con ottimi risultati. Spero che molti di voi guardino a questa nuova tecnologia come un'importante opportunità che ci viene ancora una volta offerta da quella ricchissima piattaforma di sviluppo che è Visual Studio 2005.

Happy Reporting!

Commenti
Nome

Sito web
Commento


indietro