Libreria Ajax predefinita di Asp.Net e Visual Studio

Asp.Net e Visual Studio mettono a disposizione un framework chiamato Asp.Net Ajax Library composto da elementi sia lato server che lato client.

La parte lato server include alcuni controlli Asp.Net come ScriptManager e UpdatePanel mentre per la parte client sono disponibili diverse classi JavaScript.

L'obiettivo è ottenere un'interfaccia utente più reattiva, con tempi di risposta brevi. Con Ajax è possibile effettuare in background richieste al server e poi aggiornare solo una porzione della pagina web senza dover effettuare un postback completo e dover elaborare per intero la pagina.

Un esempio è l'elenco dei contatti online su Facebook: si aggiorna di continuo senza che la pagina Web venga ricaricata per intero.

Questi tre esempi producono un risultato quasi identico: utilizzano tramite JavaScript/Ajax una funzione VB.Net definita lato server. Ognuna delle tre tecniche ha dei pro e contro, bisogna scegliere quella opportuna in base alle circostanze.

Update Panel

L'UpdatePanel è un controllo Asp.Net che definisce una porzione di pagina da aggiornare ogni volta che un controllo al suo interno genera un postback. Viene quindi aggiornata solo quella porzione di pagina, lasciando intatto il resto.

In realtà tutta la pagina viene inviata al server, ma poi viene restituito al client solo il codice necessario ad aggiornare la porzione di pagina contenuta all'interno dell'UpdatePanel. Si ha quindi una minore quantità di informazioni trasmesse in rete e non si ha l'effetto di sfarfallio come quando si aggiorna una pagina ad esempio premendo F5 o cliccando su un collegamento.

<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
	<ContentTemplate>
		<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
		<asp:Button ID="Button1" runat="server" Text="Send" />
		<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
	</ContentTemplate>
</asp:UpdatePanel>

<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
	<ProgressTemplate>
		<img src="Images/ajax-loader.gif" />
	</ProgressTemplate>
</asp:UpdateProgress>

Per poter usare la libreria Asp.Net Ajax è necessario che la pagina definisca uno ScriptManager.

Poi si definisce un UpdatePanel all'interno del quale si posizionano i controlli asp e html. In questo caso ho definito una textbox, un pulsante e una label che mostrarà il messaggio di benvenuto.

E' facoltativo definire anche un UpdateProgress con un messaggio oppure un'icona di attesa da mostrare solo quando l'UpdatePanel associato sta lavorando ed è in attesa di dati dal server.

Protected Sub Button1_Click(sender As Object, e As System.EventArgs) Handles Button1.Click
		'System.Threading.Thread.Sleep(2000)
		Label1.Text = String.Format("Welcome {0}", TextBox1.Text)
End Sub

Infine si gestisce l'evento Click del pulsante.
Il comando Thread.Sleep serve solo per testare l'icona di caricamento, che per default appare dopo 500 millisecondi.

Si ottiene questo risultato:

Aggiornare un UpdatePanel da un pulsante esterno

E' possibile fare in modo che sia un controllo esterno all'UpdatePanel a causarne l'aggiornamento.
Ad esempio si definisce un pulsante:

<asp:Button ID="Button2" runat="server" Text="ToUpper" />

Si aggiunge la sezione Triggers dichiarando il controllo esterno (in questo caso il pulsante).

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
	<ContentTemplate>
		<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
		<asp:Button ID="Button1" runat="server" Text="Send" />
		<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
	</ContentTemplate>
	<Triggers>
		<asp:AsyncPostBackTrigger ControlID="Button2" EventName="Click" />
	</Triggers>
</asp:UpdatePanel>
Protected Sub Button2_Click(sender As Object, e As System.EventArgs) Handles Button2.Click
	Label1.Text = Label1.Text.ToUpper()
End Sub

In questo esempio il secondo pulsante serve a impostare in maiuscolo i caratteri della label. La funzione quindi ha piena visibilità dei controlli definiti nell'UpdatePanel.

Page Methods

Questa tecnica consiste nel dichiarare una o più funzioni statiche (Shared) a livello di pagina aspx e renderle poi utilizzabili dal  codice JavaScript della pagina stessa.

In questo modo la quantità di dati trasmessa tra client e server è minima, ottenendo così un'interfaccia più scattante.

Di contro, la visibilità è limitata: queste funzioni lato server, essendo statiche non hanno accesso lato server ai vari controlli definiti nella pagina. In certi casi i valori necessari possono però essere passati come parametri alle funzioni.
Inoltre queste funzioni possono essere usate solo da funzioni JavaScript definite all'interno della stessa pagina.

Si parte quindi definendo la funzione statica.
Notare che è necessario importare il namespace System.Web.Services e che per rendere una funzione accessibile lato client bisogna marcarla con <WebMethod()>

Imports System.Web.Services

Partial Class PageMethod
	Inherits System.Web.UI.Page

	<WebMethod()>
	Public Shared Function Hello(ByVal Name As String) As String
		Return "Welcome " & Name
	End Function
End Class

Questa invece è la pagina .aspx

<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
</asp:ScriptManager>

<input id="txtName" type="text" />
<input id="btnHello" type="button" value="button" />


<script language="javascript" type="text/javascript">

	// Associo l'evento click del pulsante alla funzione SayHello
	$addHandler($get('btnHello'), 'click', SayHello);

	// Richiamo il metodo Hello passandogli il valore della textbox
	// e la funzione che gestirà il risultato della richiesta (HelloCallBack)
	function SayHello() {
		var yourName = $get('txtName').value;
		PageMethods.Hello(yourName, HelloCallBack);
	}

	function HelloCallBack(result) {
		alert(result);
	}

</script>

Notare l'attributo EnablePageMethods="true" dello ScriptManager.

PageMethods è un elemento predefinito della libreria Asp.Net Ajax che permette di avere accesso ai Web Methods della pagina.

Alla fine si ottiene questo:

Web Service

Ho già scritto un articolo su come utilizzare un Web Service usando JavaScript e JQuery
In questo caso invece si usa il Web Service tramite la libreria Asp.Net Ajax. Il funzionameto è molto simile.

La differenza rispetto alla tecnica dei Page Methods sta nel fatto che un Web Service è richiamabile da tutte le pagine definite nel sito.

Si crea quindi un Web Service di tipo .asmx.

Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols

'To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line
<System.Web.Script.Services.ScriptService()> _
<WebService(Namespace:="http://www.dev-oclock.com/")> _
<WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class SRB_WebServiceDemo
	Inherits System.Web.Services.WebService

	<WebMethod()> _
	Public Function Hello(ByVal Name As String) As String
		Return String.Format("Welcome {0}", Name)
	End Function

End Class

Notare che è necessario decommentare la direttiva <System.Web.Script.Services.ScriptService()>

Questa invece è la pagina .aspx

<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>

<asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server">
	<Services>
		<asp:ServiceReference Path="~/WebServiceDemo.asmx" />
	</Services>
</asp:ScriptManagerProxy>

<h2>Web Service</h2>
<input id="txtName" type="text" />
<input id="btnHello" type="button" value="button" />

<script language="javascript" type="text/javascript">

	// Associo l'evento click del pulsante btnHello alla funzione funHello
	$addHandler($get('btnHello'), 'click', funHello);

	// Richiamo il metodo Hello del Web Service passandogli il valore della textbox 'txtName'
	// e la funzione che gestirà il risultato della richiesta (HelloCallBack)
	function funHello() {
		var Name = $get('txtName').value;
		SRB_WebServiceDemo.Hello(Name, HelloCallBack);
	}

	function HelloCallBack(result) {
		alert(result);
	}

</script>

Spesso lo ScriptManager è definito nella Master Page. Non è possibile definirne più di uno in ogni pagina, ma è possibile usare gli ScriptManagerProxy.
Se il Web Service viene usato in tutte o quasi le pagine del sito, allora conviene dichiararlo direttamente nello ScriptManager.
Quando invece il WS viene usato solo in poche pagine del sito conviene definirlo in uno ScriptManagerProxy presente solo nelle pagine che lo usano.

Autore: Sergio Roberto Boarina