Questo post conclude il piccolo esempio con cui è possibile sperimentare l’uso di Silverlight 3 insieme ai .NET RIA Services, trovate le precedenti parti qui:
Usiamo il file creato in automatico da Visual Studio per aggiungere delle semplici regole di validazione. Nel mio caso il file si chiama CustomersModel.metadata.cs. Se esplorate il file troverete delle classi che si mappano su quelle del vostro modello dei dati, che espongono delle proprietà sulle quali possiamo intervenire usando opportuni attributi, ad esempio trovate commentati nello stesso file: Required, RegularExpression etc diciamo più o meno intuitivi sul loro significato.
Nel mio caso voglio impostare una semplice regola: il campo CompanyName non può essere nullo ed il relativo messaggio d’errore: “Devi inserire il nome della company”; ok, ecco come si presenta il codice, dove la parte in verde è quella da aggiungere:
Questa operazione “impostata sul server” al momento della compilazione viene “trasportata” anche nel codice proxy generato lato client.
Se ora faccio partire l’applicazione e cerco di togliere dalla Grid, che ha l’edit mode abilitato, il nome della company ottengo una “bellissima” segnalazione dell’errore di validazione. Per il test di questa situazione fate partire l’applicazione senza il debugger collegato (CTRL-F5)
La regola di validazione sta lavorando client-side, quindi senza fare round-trip con il server.
OK, aggiungiamo ora un nuovo controllo che può essere utile per visualizzare e fare l’edit di singoli item; nel nostro caso è poco utile perchè la mia grid ha già tutte le proprietà visibili ed è in edit mode, ma insomma …
Aggiungiamo il controllo in XAML e colleghiamolo alla griglia, in modo che quando l’utente cambi focalizzazione i contenuti siano tra loro collegati.
Ecco il codice:
Ed ecco il risultato a video:
Il form permette di abilitare la fase di Editing premendo il bottone a forma di matita in alto a destra, inoltre supporta già, senza ulteriori modifiche al codice, la regola di validazione che ho impostato in precedenza; in più notate anche un error-summary nella parte finale della schermata. Se abilitate l’editing sono in oltre presenti i due bottoni di Save e Cancel con cui è possibile cancellare la modifica fatta o aggiornare lo stato –in memoria- della nostra entità, cioè fino ad ora non è stata propagata nessuna modifica sul database.
Aggiungiamo un semplice bottone ed il relativo handle per il click del mouse.
CustomersDataSource è il nostro DomainContext
Provate … e questo conclude il mio esempio …
Potete scaricare l’esempio di codice da qui, per usarlo dovete modificare la stringa di connessione in modo che punti ad una istanza di SQL Server su cui è installato il db northwind. Nella prima parte di questa serie di post trovate i link a dove installare Silvelight 3 beta ed i .NET RIA Services.
Preferite i bottoni a destra …
o a sinistra …
Ecco come:
Per tutto il resto: Customization in IE8
Nel primo post di questa serie avete visto un piccolo esempio di come costruire uno strato di mid-tier che usi i .NET RIA Services, attualmente in preview. Nella parte finale ho collegato in binding una datagrid di Silverlight per visualizzare i dati, istanziando da codice il DomainContext che, in automatico con la compilazione, viene prodotto lato client. Il nostro DomainContext contiene la collezione delle entità su cui stiamo lavorando, Customers etc, i metodi per le operazioni di lettura, modifica, inserimento e cancellazione sugli stessi.
Ora rimuoviamo il codice C# , nella MainPage e per proseguire aggiungiamo l’assembly System.Windows.Ria.Controls.dll che si trova nella directory di installazione dei .NET RIA Services: “C:\Program Files\Microsoft SDKs\RIA Services\v1.0\Libraries\Silverlight” e una serie di namespace alla pagina XAML che ci serviranno più avanti:
Inoltre aggiungiamo il namespace al progetto locale che contiene il DomainContext generato dai RIA Services, nel mio caso si tratta di quello dell’applicazione web. Aggiungo anche questo namespace perchè voglio istanziare in XAML, in modo dichiarativo, l’oggetto CustomersContext che prima istanziavo in C#, quindi:
Ora, il controllo DomainDataSource, che conterrà l’istanza del nostro CustomersModel nome del metodo Loadcustomers:
Ora, uso la proprietà ItemsSource della DataGrid per collegare la proprietà Data, dell’elemento appenda dichiarato che si chiama (x:Name) customersDataSource.
Il risultato fino a qui raggiunto è lo stesso di quello ottenuto alla fine del post fatto in precedenza, ma mi dà l’occasione di continuare l’esempio…
Se ora voglio aggiungere l’ordinamento di default alla DataGrid, usando sempre l’oggetto DomainDataSource, scrivo il codice nell’immagine dove PropertyPath identifica in questo caso il nome della proprietà di cui voglio ottenere l’ordinamento dell’entità Customer.
Ora aggiungo un semplice TextBox dove l’utente può inserire l’iniziale della città per eseguire il filtraggio dei miei Customers, poi come nel caso seguente modifico il mio DomainDataSource per dare supporto al filtraggio via TextBox.
Aggiungiamo ora il controllo DataPager, impostiamo il numero di dati per pagina uguale a 5 e colleghiamo la sorgente per la paginazione sempre al nostro customersDataSource
Il risultato è quello che vedete nell’immagine sottostante:
Se ricordate all’inizio, il numero di Customers che venivano recuperati dalla query era pari a 20 e la paginazione avviene per pagine di 5 elementi. Questo vuol dire che dopo il primo roundtrip con il server che recupera i 20 clienti, la paginazione nel mio caso avviene, per quegli elementi, sul client, quindi senza andare a chiamare il server quando non è necessario.
Nella prossima parte useremo il nuovo controllo DataForm, aggiungeremo la validazione ed il supporto per le operazioni di update sul database.
I .NET RIA Services (attualmente in Preview rilasciata dopo il MIX09) sono molto interessanti per chi scrive applicazioni e vuole esporre entità tramite servizi e poi consumarle da Silverlight 3. Pensiamo ad esempio ad una piccola applicazione, costruiamo lo strato di accesso ai dati con Entity Framework, vogliamo poi costruire uno strato di servizi per esporre gli stessi dati ad un’applicazione silverlight 3.
Per seguire il mio esempio dovete avere installato:
Attenzione: se sulla vostra macchina sviluppate anche con Silverlight 2, usate una macchina virtuale per Silverlight 3 beta, perchè dopo l’installazione dei tool la macchina sarà configurata per questa versione di Silverlight, la 3 appunto e non vi sarà supporto per creare progetti Silverlight 2.
Creiamo un nuovo progetto Silverlight 3, potete anche usare il nuovo template Silverlight Navigation …
Nella maschera successiva, lasciate impostato il flag “Link to ASP.NET server project”. Questo creerà un legame tra il nostro servizio e l’applicazione client (Silverlight) generando ad ogni compilazione delle classi per Silverlight ed il relativo modello che permetteranno l’interazione con la corrispondente parte lato server.
Ora al nostro progetto aggiungiamo un semplice strato di accesso ai dati fatto con Entity Framework, usando northwind e prendendo la tabella Customers, che creerà la corrispettiva classe, immagino fino a qui sia più o meno tutto noto e le immagini seguenti siano esplicative:
Nel disegno futuro potrete usare qualunque tecnologia per lo strato di accesso ai dati usata insieme ai .NET RIA Services: LINQ to SQL, vari ORM, semplici oggetti .NET etc, etc.
Ora, sempre sul progetto web, che contiene ora il nostro file.edmx, possiamo aggiungere un DomainDataService. Questo nuovo template per VS 2008:
Quindi, Add New Item, selezionare Domain Service Class, chiamiamo il nostro servizio ad esempio CustomersService, ad esempio
Ora nella schermata seguente abbiamo la possibilità di selezionare le Entità e se abilitare la modifica su queste, questo creerà dei metodi di Update, Insert e Delete. Inoltre selezionate il flag per creare la classe dei metadati, che ci servirà dopo per la validazione.
l’opzione Enable Client Access è importante: questa crea il legame tra il mid-tier, il nostro progetto web che espone dati, ed il progetto Silverlight 3. Ogni volta che compilo l’applicazioni vengono create delle classi proxy, che si mappano sul modello.
Le classi lato server
Sul server ora vengono create due classi, la prima customerModel, contiene i metoti per ottenere/inserire/modificare e cancellare i nostri customers, le entità del nostro modello:
la classe CustomersModel.metadata.cs contiene i metadati relativi
Le classi lato client: Silverlight
Se compiliamo il progetto, vengono prodotte in automatico delle classi proxy, per vederle in Visual Studio, possiamo usare il bottone per visualizzare tutti i file:
Ora, per renderci conto di come usare i RIA Services (un primo modo per la verità), inseriamo una semplice DataGrid nel progetto Silverlight e poi scriviamo il codice seguente nel file di code-behind:
Se lancio l’applicazione ho i dati visualizzati nelle griglia:
il metodo LoadCustomers è il corrispondente metodo associato al metodo GetCustomers definito a livello di servizio. I RIA Services usano questa convenzione nella nomenclatura, che comunque può essere personalizzata e/o modificata usando l’attributo [Query] sul metodo del Servizio.
Nella prossima parte ci occuperemo di:
Direi che una buona pagina da cui partire è questo documento su MSDN :Performance Considerations for Entity Framework Applications, che punta ad una serie di risorse che ho trovato interessanti.
Beh, forse è la prima domanda che ci si pone. Cosa succede al momento della creazione dell’ObjectContext, il punto di accesso con cui usiamo EF ? In un bel post del team viene evidenziato il dettaglio delle operazioni fatte ed il relativo costo:
Da una rapida occhiata si vede come tra le operazioni che hanno più costo, in particolare allo start-up, ci sono:
Nell’ 1% c’è il tempo di esecuzione vero e proprio della query. Nello stesso post c’è anche il grafico del dettaglio di questo costo, con la spiegazione delle singole voci, tolto il tempo di start-up quindi. Vi riporto qui per comodità di lettura:
Ci potremmo chiedere. Ogni volta che creo un ObjectContext, per i tempi di start-up? O quando eseguo una query ?
Nella documentazione MSDN vediamo che alcuni di questi costi sono legati (quindi in qualche modo vivono in una cache) all’ Application Domain e non alla creazione della singola istanza di ObjectContext. Guardate la tabella seguente:
Nell’immagine vedete che i costi più alti ci sono una sola volta per ogni Application Domain.
Infatti se in una Console Application eseguite una query con due istanze dello stesso object Context, che esegue la tessa query 4 volte con il primo e altre 4 volte con il secondo, vedete il costo molto alto solo nel primissimo run:
Inoltre come detto, potrei ridurre il costo della fase di generazione delle view, come documentato qui, nel caso il mio application domain venisse creato e distrutto più volte.
Sempre dalla tabella vista in precedenza, si vedono i costi del tempo di preparazione ed esecuzione delle query sono distinti. EF fa in modo che il tempo di preparazione di ogni singola query sia speso una sola volta per query e quindi poi parte del lavoro riutilizzato. Ad ogni modo è abbastanza intuitivo pensare che all’aumentare della complessità della query i tempi di preparazione ed esecuzione aumenteranno inevitabilmente.
Per ottimizzare il tempo complessivo speso per una query è possibile utilizzare delle query compilate (Documentazione MSDN qui). Una query compilata viene creata una volta sola e puoi può essere riutilizzata con diversi parametri.
Trovate un esempio d’utilizzo in questo post del team di prodotto.
Un altro aspetto che nella tabella sopra è contraddistinto come low, ma che è proporzionale al numero di oggetti ritornati e quello relativo al tracking, questa funzionalità dell’ ObjectStateManager che tiene traccia della “vita” delle nostre entità: aggiunta, cancellazione, modifica e l’Entity Key viene usata per identificare le istanze degli stessi.
Quando usate come mergeoptions NoTracking, le operazioni di aggiornamento e risoluzione dell’identità della cache dell’ObjectStateManager non vengono eseguite. Questa opzione ha senso se non dobbiamo tracciare operazioni di modifica/cancellazione e inserimento dei nostri oggetti, ne è tipico l’uso in applicazioni ASP.NET in cui si fa il recupero di dati e non si è interessati ad altro.
Da quanto visto in precedenza appare anche un altro aspetto che può essere utile investigare : all’aumentare del numero di tabelle del db che fanno parte di uno stesso Entity Data Model (EDM) le performance decrescono. Da questi due post del team (primo e secondo) i suggerimenti sono di pensare di dividere l’EDM in più parti quando il numero di tabelle è elevato, quando cioè si raggiungono le 50-100 tabelle.
La divisione dell EDM in parti con il riutilizzo parziale di tipi tra EDM diversi non è una cosa banale, poichè il designer di Visual Studio non c’aiuta e quindi bisogna operare a mano sul file CSDL. Trovate degli esempi con diverse strategie proprio nei due post che vi segnalo.
L’ottimizzazione delle performance di EF può tenere conto di diversi aspetti, che ho cercato di ricollegare con un po’ di documentazione, direi che può essere utile almeno tenere presente di:
Il 16 Giugno a Torino si terrà il workshop di UGISS (User Group Italiano SQL Server).
L’aspetto interessante di questa segnalazione però è il “Call for Paper”, ovvero potete anche voi proporre delle sessioni tecniche su SQL Sever.
Quindi anche se non avete mai fatto una sessione in pubblico, ma conoscete bene l’argomento, può essere una buona occassione.
Concludo con le parole di Davide Mauri : “la community ha bisogno di voi!” e “Fatevi avanti!”
La nuova barra (taskbar) di Windows 7, la trovo decisamente più comoda di quella di Vista/XP.
A questo link sulla documentazione MSDN trovate come funziona dal punto dell’utente finale e soprattutto le API Win32 relative per accedere alle funzionalità dalle vostre applicazioni.
Fondamentalmente la nuova taskbar integra la Quick LanchBar : lanciate l’applicazione( ad esempio IE) e poi avete accesso alle istanze della stessa (le varie finestre/tab) del browser da uno stesso punto. Questo avviene in modo automatico se l’applicazione è in “qualche modo” pensava per la Taskbar di Win7 direttamente o indirettamente. Le nuove API win32 permetono proprio questo infatti: il poter sfruttare la taskbar e le relative funzionalità per l’utente finale da un’applicazione scritta da noi.
Se andate sopra con il mouse ad una delle applicazioni che avete messo nella taskbar e premete il tasto destro, accedete a quella che viene chiamata Jump List, che contiene i dati acceduti di recente all’applicazione, la possibilità di fare pin o meno dell’applicativo alla Taskbar etc.
Un altro aspetto interessante è la preview dei gruppi (tab) di un’applicazione, che si vede bene quando aprite più tab in IE8, come sotto:
Oppure il risultato delle progressbar vista in overlay sull’icona stessa mentre si fa il download di file:
E se lo volessimo far fare anche per una nostra applicazione, ad esempio quando sta facendo un elaborazione un po’ lunga ?
Windows 7 mette a disposizione delle API Win32 per avere accesso da un’applicazione alle funzionalità che vi ho raccontato sommariamente in precedenza. Però, come già in precedenza per Windows Vista esistevano dei Managed Wrapper per accedere a queste API nel caso vogliamo realizzare un’applicazione.NET .
In MSDN gallery trovate degli esempi già fatti che usano le Windows 7 Taskbar and Libraries .NET Interop Sample Library. Queste si basano sulla versione 1.4 modificata delle Windows Vista Bridge API.
Nella gallery trovate diversi esempi per le diverse funzionalità.
Se ad esempio volessimo visualizzare una progressbar che indica che la nostra applicazione sta facendo qualcosa di impegnativo, dobbiamo
1. Aggiungere le librerie per la gestione della taskbar di Windows 7, che sono quelle che vedete in figura:
In questo caso basta chiamare l’API SetProgressValue, come nell’esempio di codice seguente
Ora il secondo e terzo parametro rappresentano la percentuale attuale e finale di completamento dell’operazione, il secondo valore andrà aggioranto via…via, nell’esempio che trovate in MSDN Gallery viene usato un timer per la simulazione. Il risultato è quello che vedete di seguito:
Se voglio visualizzare una situazione d’errore ecco come fare:
Ed il risultato:
Gli esempi che trovate su MSDN usano per lo più semplici Windows Forms, se volete usare WPF per ottenere le stesse funzionalità vi serve avere l’handle alla Window del sistema operativo.
Si può fare tramite le API di interop con Win32 di WPF:
A questo punto Handle è il valore che dovete usare nelle API della Taskbar di Windows 7, almeno per la Progress Bar.
Ci sono molte altre API, che potete usare anche da .NET tramite queste librerie:
Potete mettere in overlay icone, creare clip per vedere meglio la preview normalmente offerta da Windows 7.
Dopo l’edizione della conferenza Basta!Italia svoltasi a Roma e a cui ho avuto il piacere di parteciapre, ecco l’edizione più snella ed itinerante, le informazioni sono sul sito. Le prime date sono a Milano il 28 ed il 29 Maggio. Dal blog del Daniele nazionale vedo che ci sarà anche una Community Night gratuita il 28 Maggio dalle 18 alle 21 … vi lascio scoprire i contenuti da soli ….