Ajax è ormai uno dei paradigmi fondamentali per la creazione di interfacce Web, questo dipende da due fattori tra loro correlati: performance migliori rispetto alle classiche applicazioni Web e una esperienza utente più fluida e simile a quella ottenuta con applicazioni desktop.
Per renderci conto della differenza in termini prestazionali, basta esaminare cosa succede nell'esempio precendente: quando schiacciamo il bottone viene effettuato un postback della pagina verso il server il quale: elabora la nuova richiesta http, individua dalle variabili in POST
, esegue il codice associato all'evento click
, effettuano il nuovo rendering della pagina e la rimanda al client.
Ora esaminiamo cosa questo implichi in termini di performance, utilizzando Fiddler, un programma che ci permette di analizzare il traffico della nostra applicazione.
Alla prima richiesta viene restituita la pagina che ha dimensioni di 2.8 Kb
, alla pressione del bottone viene effettuata una richiesta con un upload di 915 byte
e si riceve in ritorno una pagina di 2,959 Kb
. Il concetto è che per cambiare il testo di una stringa è stata effettuata una richiesta completa di tutta la pagina.
Sebbene le quantità in gioco siano piccole, possiamo immaginare cosa accade con pagine ricche di controlli ed in generale di testo, immagini etc. In questo caso, ad ogni pressione del bottone, il server deve eseguire l'evento associato al click del bottone, ma anche costruire nuovamente tutta la pagina e rilanciare tutto il rendering dei controlli.
Per l'utente inoltre, si ha la sgradevole sensazione del refresh completo anche se in realtà è stata cambiata solo una piccola porzione della pagina.Questa analisi è da tenere a mente, soprattutto in ambienti in cui le performance sono critiche.
Implementare funzionalità Ajax con WCF
La soluzione migliore è implementare le funzionalità critiche in Ajax sfruttando le potenzialità di jQuery e della libreria Microsoft Ajax. Supponiamo infatti di volere realizzare la funzionalità appena vista (cambiare il testo di una parte di pagina) effettuando una chiamata ad un servizio. Per prima cosa aggiungiamo al progetto un "AJAX-Enabled WCF Service":
Visual Studio genera un servizio in cui implementare la funzione che fornirà la stringa da visualizzare alla pressione del bottone.
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService
{
[OperationContract]
public String GetServerString()
{
return "You have clicked me at:" + DateTime.Now;
}
}
Questo è un normale web service WCF con alcuni attributi particolari che permettono di essere usato lato client. Affinché sia possibile invocare le funzioni di questo servizio da una funzione javascript si può inserire nella pagina un controllo asp.net chiamato ScriptManager ed inserire al suo interno un riferimento al servizio che si vuole chiamare.
<asp:ScriptManager ID="ScriptManager1" runat="server" >
<Services>
<asp:ServiceReference Path="~/Services/MyService.svc" />
</Services>
</asp:ScriptManager>
Il Controllo ScriptManager
è proprio della libreria Microsoft ajax ed il suo compito è gestire gli scritp javascript, la funzionalità usata in questo esempio permette di autogenerare uno script che permette di invocare il servizio referenziato in modo semplice.
Esaminando la pagina DefaultAjax.aspx
i controlli bottone
e label
sono scomparsi e sono stati sostituiti dai loro corrispondenti HTML; questo viene fatto perchè non è necessario interagire lato server.
<h2>Welcome to ASP.NET!</h2>
<input type="button" id="Button1" value="Button" />
<span id="label1">label1</span>
<p>
Tutta la funzionalità lato client viene implementata da questo script incluso nella pagina.
$(function () {
$('#Button1')
.click(function () {
MyService.GetServerString(GetServerStringReturn);
});
});
function GetServerStringReturn(result) {
$('#label1').text(result);
}
Anche se non si possiede nessuna conoscenza di jQuery lo script funziona in questo modo: la prima riga dichiara una funzione che viene eseguita al termine del caricamento della pagina, la sintassi $('#Button1')
identifica nella pagina un elemento del DOM che ha id Button1
, ed aggiunge un evento che verrà eseguito alla pressione del bottone stesso. La procedura è in qualche modo analoga a ciò che si è fatto prima, solo che in questo caso la funzione viene eseguita nel browser senza richiedere un nuovo postback.
Nel gestore dell'evento click()
viene chiamata la funzione del servizio semplicemente con l'istruzione MyService.GetServerString()
, proprio come se il servizio fosse una funzione JavaScript. Dato che l'invocazione avviene in maniera asincrona, per elaborare il risultato viene utilizzata una ulteriore funzione che verrà chiamata quando il servizio ritorna il risultato e nella quale non si fa altro che cambiare il testo dello span con il valore di ritorno della chiamata.
Se si esegue la pagina DefaultAjax.aspx
e si intercetta il traffico con fiddler. Ora possiamo notare come la presenza di alcuni script JavaScript nella pagina, prima assenti. Questi script sono introdotti dal controllo ScriptManager
e servono per abilitare le funzionalità Microsoft Ajax e per creare il codice che permette la chiamata del servizio.
L'aspetto fondamentale è che alla pressione del bottone, viene effettuata una richiesta al servizio, che risponde con la stringa
{"d":"You have clicked me at:30/03/2010 07:29:34"}
Ovvero la risposta data dal server in formato JSON.
Rispetto al caso precedente non c'è quindi necessità di rielaborare nuovamente tutti i controlli della pagina ottenendo cosi performance migliori ed indipendenti dalla dimensione della pagina stessa. Grazie ad Ajax, anche se la pagina contenesse decine di controlli e molto codice HTML, alla pressione del bottone il server eseguirebbe solamente la funzione chiama e restituirebbe sempre e solo 276 byte
.
Come ultima nota osserviamo che all'inizio del file DefaultAjax.js
è presente un commento molto particolare il cui contenuto serve solamente all'intellisense JavaScript per importare la documentazione di jQuery, automaticamente inserita nel progetto di default.
/// <reference path="Scriptsjquery-1.3.2-vsdoc.js">
In questo modo l'intellisense fornisce un valido aiuto durante la digitazione del codice.