Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Framework Ajax per ASP.NET: MagicAjax

Una libreria per interazioni Ajax molto semplice da utilizzare grazie alla sua filosofia wrapper
Una libreria per interazioni Ajax molto semplice da utilizzare grazie alla sua filosofia wrapper
Link copiato negli appunti

In questo articolo esaminiamo le potenzialità di MagicAjax: un framework tra quelli utili ad aggiungere funzionalità Ajax ad applicazioni Web già sviluppate, come accennato in un articolo procedente e secondo le intenzioni del suo creatore, Argiris Kirtzidis.

A tutti gli sviluppatori capita prima o poi l'amara esperienza di dover riadattare un progetto già portato a termine e di questi tempi capita di dover riadattare applicazioni Web già scritte, aggiungendo funzionalità Ajax.

Per evitare l'epico "lago di sangue", l'autore della libreria ha previsto una soluzione che fosse il più possibile indolore.

MagicAjax infatti ci permette infatti di raggiungere l'obiettivo aggiungendo solo una riga di codice alle classiche Web Form. Nella gran parte dei casi non sarà necessario fare altro perché le pagine non vengano ricaricate dal browser.

Esamineremo anche casi particolari in cui l'intervento richiederà qualche attenzione in più, ma anche in questo caso la parola d'ordine resta "semplicità".

Installazione

La procedura di installazione di MagicAjax è analoga a quella di qualsiasi altro componente nella piattaforma ASP.NET

Scaricare le libreria

Scarichiamo la libreria dal sito web e ne estraiamo i file sul desktop.

Nota: la dll viene fornita con un ricco corredo di esempi, per .NET 1.1 e 2.0, è disponibile il codice sorgente pronto per essere modificato con licenza GNU ed è possibile disporre anche delle versioni precedenti.

Creare riferimenti nel progetto

Creiamo un nuovo sito web su Visual Studio o VWD (File>Nuovo Sito Web) e in "Esplora soluzioni" aggiungiamo una cartella "tmp" (tasto destro sul progetto e click su "Aggiungi cartella"), poi vi copiamo il file "MagicAjax.dll".

A questo punto aggiungiamo un riferimento (tasto destro sul progetto) e selezioniamo dalla tab "Sfoglia" la dll di MagicAjax nella cartella "tmp". Infine cancelliamo la cartella "tmp"

Aggiungere i controlli nella casella degli strumenti

Clicchiamo col tasto destro nella 'Casella degli strumenti' per aggiungere una nuova scheda ("Aggiungi scheda") che chiamiamo "MagicAjax.NET", poi clicchiamo col destro sulla scheda appena creata e selezioniamo "Scegli elementi". Usiamo il pulsante "Sfoglia" per aprire il file "MagicAjax.dll" dalla cartella Bin del nostro progetto.

Infine è necessario aggiungere del codice nel web.config:

<configuration>
  <configSections>
    <section name="magicAjax"
        type="MagicAjax.Configuration.MagicAjaxSectionHandler, MagicAjax"/>
  </configSections>


  <magicAjax outputCompareMode="HashCode" tracing="false">
    <pageStore mode="NoStore" unloadStoredPage="false" cacheTimeout="5" maxConcurrentPages="5" maxPagesLimitAlert="false" />
  </magicAjax>


  <appSettings/>

  <system.web>
    <pages>
      <controls>
        <add namespace="MagicAjax.UI.Controls" assembly="MagicAjax" tagPrefix="ajax"/>
      </controls>
    </pages>
    <httpModules>
      <add name="MagicAjaxModule" type="MagicAjax.MagicAjaxModule, MagicAjax"/>
    </httpModules>
  </system.web>
</configuration>

Tralasceremo la definizione del namespace per i controlli (in <pages>) e del modulo HTTP (in <httpModules>), invece nel corso dell'articolo ci occuperemo dell'elemento <magicAjax> quando parleremo dello stato della pagina.

AjaxPanel

Come abbiamo accennato, lavorare con MagicAjax significa, nella grande maggioranza dei casi, includere i controlli che abbiamo già scritto all'interno del tag <ajax:AjaxPanel>.

Facciamo l'esempio di una semplice applicazione con un bottone ed una Label. Alla pressione del bottone appare la data corrente nella Label.

Listato 2. WebForm con AjaxPanel

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server"></head>
<body>
  <form id="form1" runat="server">

    <ajax:AjaxPanel ID="AjaxPanel1" runat="server"
        AjaxCallConnection="Asynchronous">

        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
        <asp:Button ID="Button1" runat="server" Text="Button"
            OnClick="Button1_Click" />
    </ajax:AjaxPanel>

  </form>
</body>
</html>

Listato 3. Code behind

using System;

public partial class _Default : System.Web.UI.Page
{
  protected void Button1_Click(object sender, EventArgs e)
  {
    Label1.Text = DateTime.Now.ToString();
  }
}

È utile sottolineare che il codice sottostante l'applicazione non viene minimante intaccato da alcuna nuova istruzione.

Modalità di chiamata Ajax

Osserviamo nel dettaglio il tag <ajax:AjaxPanel>. Abbiamo aggiunto l'attributo AjaxCallConnection per mostrare come scegliere la modalità di innesco della "chiamata Ajax" (AjaxCall) ovvero dell'invio dei dati al server, in sostituzione del tipico Postback.

Le modalità possibili sono tre:

  • Asynchronous (Default) tipico aggiornamento Ajax
  • Synchronous a differenza della modalità precedente, la pagina ovviamente non viene ricaricata in maniera appariscente ma rimane bloccata sino a che l'elaborazione non finisce (nel sito ufficiale è presente un gioco del tris che attraverso una AjaxCall sincrona impedisce all'utente di fare di fare una mossa sino a che il server non abbia fatto la sua)
  • None disabilita la funzionalità

Personalizzare l'attesa

Durante il caricamento della pagina, in alto a destra appare la scritta Loading... analoga per intenderci a quella del celebre GMail. Nella versione di Magic Ajax dedicata alla versione 1.1 di .NET è possibile modificare l'elemento di attesa modificando il file "AjaxCallObject.js" contenuto nella cartella "Core".

Listato 4. Modifica dell'elmento d'attesa

function CreateWaitElement() {
  var elem = document.getElementById('__AjaxCall_Wait');
  if (!elem) {
    elem = document.createElement("div");
    elem.id = '__AjaxCall_Wait';
    elem.style.position = 'absolute';
    elem.style.height = 17;
    elem.style.paddingLeft = "3px";
    elem.style.paddingRight = "3px";
    elem.style.fontSize = "11px";
    elem.style.fontFamily = 'Arial, Verdana, Tahoma';
    elem.style.border = "#000000 1px solid";
    elem.style.backgroundColor = "DimGray";
    elem.style.color = "#ffffff";
    elem.innerHTML = 'scrivi quello che ti pare';
    elem.style.visibility = 'hidden';
    document.body.insertBefore(elem, document.body.firstChild);
  }
waitElement = elem;
}

Nota: nella versione dedicate a .NET 2 oltre la modifica al file .js è necessario anche ricompilare "magicAjax.dll".

ClientEventTrigger

Questo controllo funziona come un wrapper (involucro) attorno un controllo ed intercetta e gestisce gli eventi JavaScript ad esso legati.

Possiamo assegnare tanti trigger quanti sono gli eventi che vogliamo gestire, come nell'esempio che segue.

Listato 5. Rilevare il "focus" su una TextBox: Web Form

<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

<ajax:AjaxPanel ID="AjaxPanel1" runat="server">
  <ajax:ClientEventTrigger ID="focusEventTrigger" runat="server"
      ControlID="TextBox1" EventName="focus"
      OnInvoke="focusEventTrigger_Invoke" />

  <ajax:ClientEventTrigger ID="blurEventTrigger" runat="server"
      ControlID="TextBox1" EventName="blur"
      OnInvoke="blurEventTrigger_Invoke" />
  
  <asp:Label ID="Label1" runat="server"></asp:Label>
</ajax:AjaxPanel>

Listato 6. Rilevare il "focus" su una TextBox: Code behind

protected void focusEventTrigger_Invoke(object sender, EventArgs e)
{
  Label1.Text = "TextBox ha il focus";
}

protected void blurEventTrigger_Invoke(object sender, EventArgs e)
{
  Label1.Text = "TextBox ha perso il focus";
}

Accanto alla TextBox ci sono due tag ClientEventTrigger, che rispettivamente ne gestiscono gli eventi di "focus" e "blur". Per comprenderne meglio il funzionamento esaminiamone le proprietà.

  • ControlID Identifica il controllo del quale gestiremo l'evento JavaScript
  • EventName Mappa il preciso evento JavaScript, client side del controllo identificato da ControlID. Per identificare l'evento è sufficiente cancellare il prefisso "on" dal nome completo dell'evento (OnFocus e OnBlur diventano focus e blur).
  • OnInvoke Innesca un evento .NET, server side, che entra in azione al posto dell'evento JavaScript, client side.

Gli eventi JavaScript mappati sono quelli relativi al DOM di IE 6, Firefox 1.5 e Opera 9

KeyClientEventWrapper

Come suggerisce il nome stesso questo controllo permette di gestire lato server gli eventi lato client legati all'uso della tastiera:

  • OnKeyUp Quando un pulsante viene rilasciato
  • OnKeyDown Quando un pulsante viene premuto
  • OnKeyPress Quando un pulsante viene genericamente premuto

Questo controllo intercetta gli eventi legati a tutti i controlli in esso contenuti. Si capisce facilmente gaurdando alla posizione che ha la TextBox nel codice del prossimo esempio.

Listato 7. Intercettare gli eventi tastiera di una TextBox: Web Form

<ajax:AjaxPanel ID="AjaxPanel2" runat="server">

<ajax:KeyClientEventWrapper ID="KeyClientEventWrapper1" runat="server"
      OnKeyPress="KeyClientEventWrapper1_KeyPress">


  <!-- intercetta gli eventi di tastiera di tutti
       i controlli presenti in questo spazio -->

  <asp:TextBox ID="TextBox2" runat="server"/>

</ajax:KeyClientEventWrapper>

<asp:Label ID="Label1" runat="server"></asp:Label>

</ajax:AjaxPanel>

Listato 8. Intercettare gli eventi tastiera di una TextBox: Code behind

protected void KeyClientEventWrapper1_KeyPress(object sender,
          MagicAjax.UI.Controls.KeyPressEventArgs e)
{
  char tasto_premuto = e.KeyChar;
  Label1.Text = String.Format("L'utente ha premuto il tasto '{0}'", tasto_premuto);
}

Nota: Nella firma per gli eventi OnKeyDown e OnKeyUp usiamo come classe di argomenti MagicAjax.UI.Controls.KeyEventArgs.

Ottimizzazione della pagina MagicAjax

Questo paragrafo è posto al di fuori del procedere graduale degli esempi e tratta alcune informazioni utili per ottimizzare le nostre applicazioni ovvero ridurre il volume dei dati inviati al server durante l'AjaxCall.

Quando invochiamo una chiamata Ajax, viene simulato da JavaScript il tipico postback: tutti gli elementi della pagina (CheckBox, TextBox, campi hidden, etc.) sono inviati al server per essere elaborati.

Naturalmente sarebbe preferibile inviare solo i valori di un singolo controllo, un TextBox ad esempio, evitando di inviare i valori dell'intera pagina con un notevole risparmio di banda specie se il nostro sito ha molti utenti.

Ragguppare i controlli in "zone"

È possibile raggruppare gli elementi interessati all'AjaxCall all'interno di un elemento AjaxZone ed escludere dalla chiamata tutti gli altri elementi della pagina.

Come si vede nell'esempio che segue, AjaxZone sostituisce l'AjaxPanel, infatti definire un elemento <ajax:AjaxZone> è equivalente a definire <ajax:AjaxPanel AjaxLocalscope="true>, anche il risultato è il medesimo. Inoltre è possibile avere più livelli di nidificazione inserendo una zona nell'altra.

Listato 9. Due zone con aggiornamento autonomo: WebForm

<ajax:AjaxZone BackColor="BlanchedAlmond" ID="AjaxZone1" runat="server">
  <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    <asp:Button ID="Button1" runat="server" Text="Reload Ajax" OnClick="Button1_Click" />
  <asp:Label ID="Label1" runat="server"></asp:Label>
</ajax:AjaxZone>

<br /><br />

<ajax:AjaxZone BackColor="Azure" ID="AjaxZone2" runat="server">
  <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
    <asp:Button ID="Button2" runat="server" Text="Reload Ajax 2" OnClick="Button2_Click" />
  <asp:Label ID="Label2" runat="server"></asp:Label>
</ajax:AjaxZone>

Listato 10. Due zone con aggiornamento autonomo: Code behind

using System;

public partial class _Default : System.Web.UI.Page
{
  protected void Button1_Click(object sender, EventArgs e)
  {
    Label1.Text = TextBox1.Text;
  }

  protected void Button2_Click(object sender, EventArgs e)
  {
    Label2.Text = TextBox2.Text;
  }
}

Escludere elementi dall'invio

È anche possibile escludere dall'invio innescato dall'AjaxCall intere porzioni di Web Form impostando opportunamente i flag nell'attributo ExcludeFlags di AjaxPanel.

<ajax:AjaxPanel ID="{id_pannello}" ExcludeFlags="{impostazioni}" runat="server">

Esaminiamo le possibili "impostazioni" dei flag:

Nome Flag Valore binario Valore decimale Comportamento
excfViewState 0001 1 Il campo ViewState è escluso dall'invio.
excfFingerprints 0010 2 Le fingerprints (impronte digitali) sono contrassegni che MagicAjax assegna automaticamente ed in maniera trasparente ad ogni AjaxPanel durante l'AjaxCall; vengono confrontate ad ogni invio e se sono cambiate vengono modificate; in alcuni casi diventano superflue (ad esempio in una pagina che mostra periodicamente l'orario del server) e quindi possono essere escluse dall'invio.
excfUserHidden 0100 4 Esclude i valori passati dagli HiddenField inseriti dallo sviluppatore.
excfAllHidden 0111 7 Esclude i valori passati da tutti gli "HiddenField" presenti nella Web Form (somma logica dei primi tre flag)
excfFormElements 1000 8 Esclude solo gli elementi della Web Form
excfAllElements 1111 15 Esclude tutti gli elementi di una pagina (somma logica di tutte le esclusioni singole: excfAllHidden | excfFormElements)

È possibile definire le esclusioni sia con i nomi mnemonici:

<ajax:AjaxPanel ID="AjaxPanel1" ExcludeFlags="excfViewState" runat="server">

... sia utilizzando il codice numerico

<ajax:AjaxPanel ID="AjaxPanel1" ExcludeFlags="1" runat="server">

Infine è possibile stabilire una ottimizzazione ancora più granulare impostando le proprietà di uno o più controlli. Esaminiamo due impostazioni di attributi in particolare:

  • ajaxcall="none" Se desideriamo inviare i valori del controllo attraverso un normale postback
  • ExcludeFromPost="true" Se desideriamo escludere il controllo dall'AjaxCall

Nota: queste proprietà non sono documentate.

Lo stato della pagina durante l'AjaxCall

Il seguente paragrafo può essere utile nel caso di Web Form particolarmente complesse. Tipicamente ogni volta che invochiamo una AjaxCall, la pagina e tutti i relativi controlli vengono ricreati completamente e non viene conservato lo stato di nulla.

La prima conseguenza di tutto questo è la nota impossibilità di mantenere la storia della navigazione, ovvero di usare il tasto "Indietro". MagicAjax consente di mantenere lo stato delle pagina attraverso successivi AjaxCall.

Per comprendere questa funzionalità rifacciamoci all'esempio "PageStore" (fornito da Argiris Kirtzidis) allegato all'articolo.

Premendo il bottone grande aggiungiamo altri bottoni numerati progressivamente: è possibile contare quante volte il bottone grande è cliccato e pure controllare quale bottone, tra quelli aggiunti è stato premuto.

Figura 1. Esempio di pageStore
Esempio di pageStore

Tutto ciò è possibile se lo stato delle pagine inviate attraverso l'AjaxCall è conservato nelle Session dell'applicazione. Nel dettaglio questa funzionalità, nome in codice pageStore, viene impostata nel web.config.

<pageStoremode="Session" maxConcurrentPages="5" maxPagesLimitAlert="false"/>

È possibile definire altre proprietà a corredo: se in una sessione del browser viene aperta la stessa pagina su molte finestre, MagicAjax conserverà lo stato di ognuna sino al limite stabilito dalla proprietà maxConcurrentPages.

Una volta raggiunto il limite stabilito, durante la fase di sviluppo, il programmatore può essere avvertito da un alert impostato nella proprietà (booleana) maxPagesLimitAlert.

Nota: Questa tecnica di ottimizzazione è valida solo se impiegata in ASP.NET 1.1 e se lo stato della sessione è conservato nella modalità predefinita 'InProc'.

Se la vostra applicazione memorizza l'oggetto Session in modalità OutProc, in SQL Server, o non lo conserva affatto, dovete semplicemente impostare la proprietà PageStore su Cache per fare in modo che lo stato sia conservato nella cache del server.

<pageStoremode="Cache" cacheTimeout="5"/>

La proprietà cacheTimeout specifica quanti minuti la pagina deve essere conservata.

Conclusioni

Abbiamo esplorato le principali caratteristiche di questo componente, particolarmente utile per applicazioni pre-esistenti e comunque per realizzare applicazioni "Ajax" senza complicare troppo la vita dello sviluppatore.

Abbiamo esaminato però, solo le funzionalità "note" di MagicAjax. Nella documentazione ufficiale non esiste alcuno schema della classe che ci potrebbe essere d'aiuto qualora dovessimo fare interventi più profondi a livello di codice. MagicAjax è comunque Open Source e possiamo quindi dare un'occhiata al sorgente per conoscere meglio le relative proprietà e metodi.

Ti consigliamo anche