Usare AJAX per distribuire aggiornamenti dinamici

di Microsoft

Scarica il PDF

Questo è il passaggio 10 di un'esercitazione gratuita sull'applicazione "NerdDinner" che illustra come creare un'applicazione Web di piccole dimensioni, ma completa, usando ASP.NET MVC 1.

Il passaggio 10 implementa il supporto per gli utenti connessi a RSVP per partecipare a una cena, usando un approccio basato su Ajax integrato all'interno della pagina dei dettagli della cena.

Se si usa ASP.NET MVC 3, è consigliabile seguire le esercitazioni Introduzione Con MVC 3 o MVC Music Store.

NerdDinner Step 10: AJAX Enabling RSVPs accetta

A questo punto è possibile implementare il supporto per gli utenti connessi a RSVP per partecipare a una cena. Verrà abilitato usando un approccio basato su AJAX integrato all'interno della pagina dei dettagli della cena.

Indica se l'utente è RSVP'd

Gli utenti possono visitare l'URL /Dinners/Details/[id] per visualizzare i dettagli su una cena specifica:

Screenshot della pagina Web Nerd Dinner con i dettagli sulla cena.

Il metodo di azione Details() viene implementato come segue:

//
// GET: /Dinners/Details/2

public ActionResult Details(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (dinner == null)
        return View("NotFound");
    else
        return View(dinner);
}

Il primo passaggio per implementare il supporto RSVP consiste nell'aggiungere un metodo helper "IsUserRegistered(username)" all'oggetto Dinner (all'interno della classe parziale Dinner.cs creata in precedenza). Questo metodo helper restituisce true o false a seconda che l'utente sia attualmente RSVP'd per dinner:

public partial class Dinner {

    public bool IsUserRegistered(string userName) {
        return RSVPs.Any(r => r.AttendeeName.Equals(userName, StringComparison.InvariantCultureIgnoreCase));
    }
}

È quindi possibile aggiungere il codice seguente al modello di visualizzazione Details.aspx per visualizzare un messaggio appropriato che indica se l'utente è registrato o meno per l'evento:

<% if (Request.IsAuthenticated) { %>
 
    <% if (Model.IsUserRegistered(Context.User.Identity.Name)) { %>       

        <p>You are registred for this event!</p>
    
    <% } else {  %>  
    
        <p>You are not registered for this event</p>
        
    <% }  %>
    
<% } else { %>
 
    <a href="/Account/Logon">Logon</a> to RSVP for this event.

<% } %>

E ora quando un utente visita una cena, viene visualizzato questo messaggio:

Screenshot della pagina dei dettagli di Nerd Dinners, il messaggio Che sei registrato per questo evento viene visualizzato nella parte inferiore.

E quando visitano una cena non sono registrati per visualizzare il messaggio seguente:

Screenshot della pagina dei dettagli Delle cene nerd. Viene visualizzato il messaggio Non registrato per questo evento.

Implementazione del metodo di azione Register

Aggiungere ora la funzionalità necessaria per abilitare gli utenti a RSVP per una cena dalla pagina dei dettagli.

Per implementare questa operazione, verrà creata una nuova classe "RSVPController" facendo clic con il pulsante destro del mouse sulla directory \Controllers e scegliendo il comando di menu Aggiungi controller>.

Verrà implementato un metodo di azione "Register" all'interno della nuova classe RSVPController che accetta un ID per un oggetto Dinner come argomento, recupera l'oggetto Dinner appropriato, verifica se l'utente connesso è attualmente nell'elenco degli utenti che lo hanno registrato e, se non aggiunge un oggetto RSVP per loro:

public class RSVPController : Controller {

    DinnerRepository dinnerRepository = new DinnerRepository();

    //
    // AJAX: /Dinners/RSVPForEvent/1

    [Authorize, AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Register(int id) {

        Dinner dinner = dinnerRepository.GetDinner(id);

        if (!dinner.IsUserRegistered(User.Identity.Name)) {
        
            RSVP rsvp = new RSVP();
            rsvp.AttendeeName = User.Identity.Name;

            dinner.RSVPs.Add(rsvp);
            dinnerRepository.Save();
        }

        return Content("Thanks - we'll see you there!");
    }
}

Si noti che sopra viene restituita una stringa semplice come output del metodo di azione. Questo messaggio potrebbe essere stato incorporato all'interno di un modello di visualizzazione, ma poiché è così piccolo si userà solo il metodo helper Content() nella classe di base del controller e restituire un messaggio stringa come sopra.

Chiamata del metodo di azione RSVPForEvent tramite AJAX

Si userà AJAX per richiamare il metodo di azione Register dalla visualizzazione Dettagli. L'implementazione di questo è piuttosto semplice. Aggiungere prima di tutto due riferimenti alla libreria di script:

<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>

La prima libreria fa riferimento alla libreria di script lato client AJAX ASP.NET core. Questo file è di circa 24.000 dimensioni (compresse) e contiene la funzionalità AJAX sul lato client principale. La seconda libreria contiene funzioni di utilità che si integrano con ASP.NET metodi helper AJAX predefiniti di MVC (che verranno usati a breve).

È quindi possibile aggiornare il codice del modello di visualizzazione aggiunto in precedenza in modo che invece di restituire un messaggio "You are not registered for this event" (Non si è registrati per questo evento), viene invece eseguito il rendering di un collegamento che quando viene eseguito il push esegue una chiamata AJAX che richiama il metodo di azione RSVPForEvent sul controller RSVP e gli RSVPs dell'utente:

<div id="rsvpmsg">

<% if(Request.IsAuthenticated) { %>
 
    <% if(Model.IsUserRegistered(Context.User.Identity.Name)) { %>       

        <p>You are registred for this event!</p>

    <% } else { %>  
    
        <%= Ajax.ActionLink( "RSVP for this event",
                             "Register", "RSVP",
                             new { id=Model.DinnerID }, 
                             new AjaxOptions { UpdateTargetId="rsvpmsg"}) %>         
    <% } %>
    
<% } else { %>
 
    <a href="/Account/Logon">Logon</a> to RSVP for this event.

<% } %>
    
</div>

Il metodo helper Ajax.ActionLink() usato in precedenza è integrato ASP.NET MVC ed è simile al metodo helper Html.ActionLink(), ad eccezione del fatto che anziché eseguire una navigazione standard esegue una chiamata AJAX al metodo di azione quando si fa clic sul collegamento. Sopra viene chiamato il metodo di azione "Register" nel controller "RSVP" e passando dinnerID come parametro "id". Il parametro AjaxOptions finale che viene passato indica che si vuole accettare il contenuto restituito dal metodo action e aggiornare l'elemento div> HTML <nella pagina il cui ID è "rsvpmsg".

E ora quando un utente passa a una cena per cui non è ancora registrato, viene visualizzato un collegamento a RSVP:

Screenshot della pagina Nerd Dinners con il pulsante R S V P nella parte inferiore.

Se si fa clic sul collegamento "RSVP per questo evento", verrà eseguita una chiamata AJAX al metodo di azione Register nel controller RSVP e al termine verrà visualizzato un messaggio aggiornato, come illustrato di seguito:

Screenshot della pagina dei dettagli della cena nerd con il messaggio Grazie Vi vedremo nella parte inferiore.

La larghezza di banda e il traffico di rete coinvolti quando si effettua questa chiamata AJAX è davvero leggero. Quando l'utente fa clic sul collegamento "RSVP per questo evento", viene effettuata una piccola richiesta di rete HTTP POST all'URL /Dinners/Register/1 simile al seguente:

POST /Dinners/Register/49 HTTP/1.1
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Referer: http://localhost:8080/Dinners/Details/49

E la risposta del metodo registra azione è semplicemente:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 29
Thanks - we'll see you there!

Questa chiamata leggera è veloce e funzionerà anche su una rete lenta.

Aggiunta di un'animazione jQuery

La funzionalità AJAX implementata funziona bene e veloce. A volte può verificarsi così velocemente, tuttavia, che un utente potrebbe non notare che il collegamento RSVP è stato sostituito con nuovo testo. Per rendere il risultato un po' più ovvio, è possibile aggiungere una semplice animazione per attirare l'attenzione sul messaggio di aggiornamento.

Il modello di progetto MVC predefinito ASP.NET include jQuery, una libreria JavaScript eccellente (e molto popolare open source) supportata anche da Microsoft. jQuery offre una serie di funzionalità, tra cui una bella libreria di effetti e selezione DOM HTML.

Per usare jQuery, aggiungeremo prima un riferimento allo script. Poiché si userà jQuery all'interno di un'ampia gamma di posizioni all'interno del sito, si aggiungerà il riferimento allo script all'interno del file di pagina master Site.master in modo che tutte le pagine possano usarlo.

<script src="/Scripts/jQuery-1.3.2.js" type="text/javascript"></script>

Il codice scritto usando JQuery usa spesso un metodo JavaScript globale "$()" che recupera uno o più elementi HTML usando un selettore CSS. Ad esempio, $("#rsvpmsg") seleziona qualsiasi elemento HTML con l'ID di rsvpmsg, mentre $(".something") seleziona tutti gli elementi con il nome della classe CSS "something". È anche possibile scrivere query più avanzate, ad esempio "restituire tutti i pulsanti di opzione selezionati" usando una query del selettore, ad esempio: $("input[@type=radio][@checked]")).

Dopo aver selezionato gli elementi, è possibile chiamare metodi su di essi per intervenire, ad esempio nascondendoli: $("#rsvpmsg").hide();

Per lo scenario RSVP si definirà una semplice funzione JavaScript denominata "AnimateRSVPMessage" che seleziona il div> "rsvpmsg" <e aggiunge un'animazione alle dimensioni del contenuto di testo. Il codice seguente avvia il testo piccolo e quindi lo fa aumentare in un intervallo di tempo di 400 millisecondi:

<script type="text/javascript">

    function AnimateRSVPMessage() {
        $("#rsvpmsg").animate({fontSize: "1.5em"},400);
    }

</script>

È quindi possibile collegare questa funzione JavaScript da chiamare dopo il completamento della chiamata AJAX passandone il nome al metodo helper Ajax.ActionLink() tramite la proprietà dell'evento AjaxOptions "OnSuccess"):

<%= Ajax.ActionLink( "RSVP for this event",
                     "Register", "RSVP",
                     new { id=Model.DinnerID }, 
                     new AjaxOptions { UpdateTargetId="rsvpmsg",
                                       OnSuccess="AnimateRSVPMessage"}) %>

E ora quando si fa clic sul collegamento "RSVP per questo evento" e la chiamata AJAX viene completata correttamente, il messaggio di contenuto inviato verrà animato e crescerà di grandi dimensioni:

Screenshot della pagina Nerd Dinners con il messaggio Grazie We Will See You There in grande stampa nella parte inferiore.

Oltre a fornire un evento "OnSuccess", l'oggetto AjaxOptions espone gli eventi OnBegin, OnFailure e OnComplete che è possibile gestire (insieme a un'ampia gamma di altre proprietà e opzioni utili).

Pulizia - Effettuare il refactoring di una visualizzazione parziale RSVP

Il modello di visualizzazione dei dettagli sta iniziando a ottenere un po ' di tempo, che lo renderà un po 'più difficile da comprendere. Per migliorare la leggibilità del codice, è possibile terminare creando una visualizzazione parziale, RSVPStatus.ascx, che incapsula tutto il codice di visualizzazione RSVP per la pagina Dettagli.

A tale scopo, fare clic con il pulsante destro del mouse sulla cartella \Views\Dinners e scegliere il comando di menu Aggiungi visualizzazione>. Sarà necessario un oggetto Dinner come viewModel fortemente tipizzato. È quindi possibile copiare/incollare il contenuto RSVP dalla visualizzazione Details.aspx.

Una volta completata questa operazione, verrà creata anche un'altra visualizzazione parziale, EditAndDeleteLinks.ascx, che incapsula il codice della visualizzazione collegamento Modifica ed Elimina. Sarà anche necessario usare un oggetto Dinner come viewModel fortemente tipizzato e copiare/incollare la logica Modifica ed Elimina dalla visualizzazione Details.aspx.

Il modello di visualizzazione dei dettagli può quindi includere solo due chiamate al metodo Html.RenderPartial() nella parte inferiore:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent"runat="server">
    <%= Html.Encode(Model.Title) %>
</asp:Content>

<asp:Content ID="details" ContentPlaceHolderID="MainContent" runat="server">

    <div id="dinnerDiv">

        <h2><%=Html.Encode(Model.Title) %></h2>
        <p>
            <strong>When:</strong> 
            <%=Model.EventDate.ToShortDateString() %> 

            <strong>@</strong>
            <%=Model.EventDate.ToShortTimeString() %>
        </p>
        <p>
            <strong>Where:</strong> 
            <%=Html.Encode(Model.Address) %>,
            <%=Html.Encode(Model.Country) %>
        </p>
         <p>
            <strong>Description:</strong> 
            <%=Html.Encode(Model.Description) %>
        </p>       
        <p>
            <strong>Organizer:</strong> 
            <%=Html.Encode(Model.HostedBy) %>
            (<%=Html.Encode(Model.ContactPhone) %>)
        </p>
    
        <% Html.RenderPartial("RSVPStatus"); %>
        <% Html.RenderPartial("EditAndDeleteLinks"); %>
 
    </div>
         
</asp:Content>

In questo modo il codice risulta più pulito per leggere e gestire.

passaggio successivo

Si esamini ora come è possibile usare AJAX ulteriormente e aggiungere il supporto per il mapping interattivo all'applicazione.