Freigeben über


Iteration 7 – Hinzufügen von AJAX-Funktionen (C#)

von Microsoft

Code herunterladen

In der siebten Iteration verbessern wir die Reaktionsfähigkeit und Leistung unserer Anwendung, indem wir Ajax-Unterstützung hinzufügen.

Erstellen einer Kontaktverwaltung ASP.NET MVC-Anwendung (C#)

In dieser Reihe von Tutorials erstellen wir eine gesamte Kontaktverwaltungsanwendung von Anfang bis Ende. Mit der Contact Manager-Anwendung können Sie Kontaktinformationen – Namen, Telefonnummern und E-Mail-Adressen – für eine Personenliste speichern.

Wir erstellen die Anwendung über mehrere Iterationen. Mit jeder Iteration verbessern wir die Anwendung schrittweise. Das Ziel dieses Mehrfachiterationsansatzes besteht darin, ihnen zu ermöglichen, den Grund für jede Änderung zu verstehen.

  • Iteration Nr. 1: Erstellen Sie die Anwendung. In der ersten Iteration erstellen wir den Contact Manager auf die einfachste Weise. Wir fügen Unterstützung für grundlegende Datenbankvorgänge hinzu: Erstellen, Lesen, Aktualisieren und Löschen (CRUD).

  • Iteration Nr. 2: Sorgen Sie dafür, dass die Anwendung gut aussieht. In dieser Iteration verbessern wir das Erscheinungsbild der Anwendung, indem wir die Standardansicht ASP.NET MVC master Seite und cascading Stylesheet ändern.

  • Iteration Nr. 3: Hinzufügen der Formularvalidierung In der dritten Iteration fügen wir eine grundlegende Formularüberprüfung hinzu. Wir verhindern, dass Personen ein Formular einreichen, ohne die erforderlichen Formularfelder ausfüllen zu müssen. Außerdem überprüfen wir E-Mail-Adressen und Telefonnummern.

  • Iteration Nr. 4: Machen Sie die Anwendung lose gekoppelt. In dieser vierten Iteration nutzen wir mehrere Softwareentwurfsmuster, um die Verwaltung und Änderung der Contact Manager-Anwendung zu vereinfachen. Beispielsweise umgestalten wir unsere Anwendung so, dass sie das Repositorymuster und das Dependency Injection-Muster verwendet.

  • Iteration 5: Erstellen von Komponententests. In der fünften Iteration vereinfachen wir die Wartung und Änderung unserer Anwendung, indem wir Komponententests hinzufügen. Wir simulieren unsere Datenmodellklassen und erstellen Komponententests für unsere Controller und die Validierungslogik.

  • Iteration #6: Verwenden sie die testgesteuerte Entwicklung. In dieser sechsten Iteration fügen wir unserer Anwendung neue Funktionen hinzu, indem wir zuerst Komponententests schreiben und Code für die Komponententests schreiben. In dieser Iteration fügen wir Kontaktgruppen hinzu.

  • Iteration #7: Hinzufügen von Ajax-Funktionen. In der siebten Iteration verbessern wir die Reaktionsfähigkeit und Leistung unserer Anwendung, indem wir Ajax-Unterstützung hinzufügen.

Diese Iteration

In dieser Iteration der Contact Manager-Anwendung umgestalten wir die Anwendung so, dass ajax verwendet wird. Durch die Nutzung von Ajax machen wir unsere Anwendung reaktionsfähiger. Wir können das Rendern einer gesamten Seite vermeiden, wenn wir nur einen bestimmten Bereich auf einer Seite aktualisieren müssen.

Wir werden unsere Indexansicht umgestalten, sodass wir nicht die gesamte Seite erneut anzeigen müssen, wenn jemand eine neue Kontaktgruppe auswählt. Wenn jemand stattdessen auf eine Kontaktgruppe klickt, aktualisieren wir einfach die Liste der Kontakte und lassen den Rest der Seite in Ruhe.

Außerdem ändern wir die Funktionsweise des Löschlinks. Anstatt eine separate Bestätigungsseite anzuzeigen, wird ein JavaScript-Bestätigungsdialogfeld angezeigt. Wenn Sie bestätigen, dass Sie einen Kontakt löschen möchten, wird ein HTTP DELETE-Vorgang für den Server ausgeführt, um den Kontaktdatensatz aus der Datenbank zu löschen.

Darüber hinaus nutzen wir jQuery, um der Indexansicht Animationseffekte hinzuzufügen. Wir zeigen eine Animation an, wenn die neue Kontaktliste vom Server abgerufen wird.

Schließlich nutzen wir die Unterstützung des ASP.NET AJAX-Frameworks für die Verwaltung des Browserverlaufs. Wir erstellen Verlaufspunkte, wenn wir einen Ajax-Aufruf ausführen, um die Kontaktliste zu aktualisieren. Auf diese Weise funktionieren die Rückwärts- und Vorwärtsschaltflächen des Browsers.

Gründe für die Verwendung von Ajax

Die Verwendung von Ajax hat viele Vorteile. Erstens führt das Hinzufügen von AJAX-Funktionen zu einer Anwendung zu einer besseren Benutzererfahrung. In einer normalen Webanwendung muss jedes Mal, wenn ein Benutzer eine Aktion ausführt, die gesamte Seite auf den Server zurückgesendet werden. Wenn Sie eine Aktion ausführen, wird der Browser gesperrt, und der Benutzer muss warten, bis die gesamte Seite abgerufen und erneut angezeigt wird.

Dies wäre im Fall einer Desktopanwendung eine inakzeptable Erfahrung. Aber traditionell haben wir mit dieser schlechten Benutzererfahrung im Fall einer Webanwendung gelebt, weil wir nicht wussten, dass wir es besser machen konnten. Wir dachten, es sei eine Einschränkung von Webanwendungen, wenn es in Wirklichkeit nur eine Einschränkung unserer Vorstellungskraft war.

In einer Ajax-Anwendung müssen Sie die Benutzererfahrung nicht zum Stillstand bringen, nur um eine Seite zu aktualisieren. Stattdessen können Sie eine asynchrone Anforderung im Hintergrund ausführen, um die Seite zu aktualisieren. Sie zwingen den Benutzer nicht, zu warten, bis ein Teil der Seite aktualisiert wird.

Durch die Nutzung von Ajax können Sie auch die Leistung Ihrer Anwendung verbessern. Überlegen Sie, wie die Contact Manager-Anwendung derzeit ohne AJAX-Funktionalität funktioniert. Wenn Sie auf eine Kontaktgruppe klicken, muss die gesamte Indexansicht erneut angezeigt werden. Die Liste der Kontakte und die Liste der Kontaktgruppen müssen vom Datenbankserver abgerufen werden. Alle diese Daten müssen über die Leitung vom Webserver an den Webbrowser übergeben werden.

Nachdem wir der Anwendung Ajax-Funktionen hinzugefügt haben, können wir jedoch vermeiden, dass die gesamte Seite erneut angezeigt wird, wenn ein Benutzer auf eine Kontaktgruppe klickt. Wir müssen die Kontaktgruppen nicht mehr aus der Datenbank abrufen. Wir müssen auch nicht die gesamte Indexansicht über das Kabel übertragen. Durch die Nutzung von Ajax reduzieren wir den Arbeitsaufwand, den unser Datenbankserver ausführen muss, und wir reduzieren den Netzwerkdatenverkehr, der von unserer Anwendung benötigt wird.

Keine Angst vor Ajax

Einige Entwickler vermeiden die Verwendung von Ajax, da sie sich Gedanken über Downlevel-Browser machen. Sie möchten sicherstellen, dass ihre Webanwendungen weiterhin funktionieren, wenn auf einen Browser zugegriffen wird, der JavaScript nicht unterstützt. Da Ajax von JavaScript abhängt, vermeiden einige Entwickler die Verwendung von Ajax.

Wenn Sie jedoch vorsichtig sind, wie Sie Ajax implementieren, können Sie Anwendungen erstellen, die sowohl mit Uplevel- als auch downlevel-Browsern funktionieren. Unsere Contact Manager-Anwendung funktioniert mit Browsern, die JavaScript unterstützen, und Browsern, die dies nicht tun.

Wenn Sie die Contact Manager-Anwendung mit einem Browser verwenden, der JavaScript unterstützt, erhalten Sie eine bessere Benutzererfahrung. Wenn Sie beispielsweise auf eine Kontaktgruppe klicken, wird nur der Bereich der Seite aktualisiert, in der Kontakte angezeigt werden.

Wenn Sie dagegen die Contact Manager-Anwendung mit einem Browser verwenden, der JavaScript nicht unterstützt (oder JavaScript deaktiviert ist), haben Sie eine etwas weniger wünschenswerte Benutzererfahrung. Wenn Sie beispielsweise auf eine Kontaktgruppe klicken, muss die gesamte Indexansicht zurück in den Browser gepostet werden, um die übereinstimmende Kontaktliste anzuzeigen.

Hinzufügen der erforderlichen JavaScript-Dateien

Wir müssen drei JavaScript-Dateien verwenden, um ajax-Funktionen zu unserer Anwendung hinzuzufügen. Alle drei Dateien sind im Ordner Skripts einer neuen ASP.NET MVC-Anwendung enthalten.

Wenn Sie ajax auf mehreren Seiten in Ihrer Anwendung verwenden möchten, ist es sinnvoll, die erforderlichen JavaScript-Dateien in die Ansicht Ihrer Anwendung master Seite einzuschließen. Auf diese Weise werden die JavaScript-Dateien automatisch auf allen Seiten in Ihrer Anwendung eingeschlossen.

Fügen Sie die folgenden JavaScript-Elemente innerhalb des <Haupttags> Ihrer Ansicht master Seite hinzu:

<script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
    <script src="../../Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
    <script src="../../Scripts/jquery-1.2.6.min.js" type="text/javascript"></script>

Umgestalten der Indexansicht zur Verwendung von Ajax

Ändern Sie zunächst unsere Indexansicht, sodass durch Klicken auf eine Kontaktgruppe nur der Bereich der Ansicht aktualisiert wird, in der Kontakte angezeigt werden. Das rote Feld in Abbildung 1 enthält den Bereich, den wir aktualisieren möchten.

Nur Kontakte aktualisieren

Abbildung 01: Nur Kontakte aktualisieren(Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Der erste Schritt besteht darin, den Teil der Ansicht, den wir asynchron aktualisieren möchten, in ein separates partielles (Ansichtsbenutzersteuerelement) zu trennen. Der Abschnitt der Indexansicht, in dem die Tabelle der Kontakte angezeigt wird, wurde in den Teil in Listing 1 verschoben.

Auflistung 1 : Views\Contact\ContactList.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ContactManager.Models.Group>" %>
<%@ Import Namespace="Helpers" %>
<table class="data-table" cellpadding="0" cellspacing="0">
    <thead>
        <tr>
            <th class="actions edit">
                Edit
            </th>
            <th class="actions delete">
                Delete
            </th>
            <th>
                Name
            </th>
            <th>
                Phone
            </th>
            <th>
                Email
            </th>
        </tr>
    </thead>
    <tbody>
        <% foreach (var item in Model.Contacts)
           { %>
        <tr>
            <td class="actions edit">
                <a href='<%= Url.Action("Edit", new {id=item.Id}) %>'><img src="../../Content/Edit.png" alt="Edit" /></a>
            </td>
            <td class="actions delete">
                <a href='<%= Url.Action("Delete", new {id=item.Id}) %>'><img src="../../Content/Delete.png" alt="Edit" /></a>
            </td>
            <th>
                <%= Html.Encode(item.FirstName) %>
                <%= Html.Encode(item.LastName) %>
            </th>
            <td>
                <%= Html.Encode(item.Phone) %>
            </td>
            <td>
                <%= Html.Encode(item.Email) %>
            </td>
        </tr>
        <% } %>
    </tbody>
</table>

Beachten Sie, dass die partielle in Listing 1 ein anderes Modell hat als die Indexansicht. Das Inherits-Attribut in der <%@ Page %> -Direktive gibt an, dass der Teil von der ViewUserControl<Group-Klasse> erbt.

Die aktualisierte Indexansicht ist in Listing 2 enthalten.

Auflistung 2 : Views\Contact\Index.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ContactManager.Models.ViewData.IndexModel>" %>
<%@ Import Namespace="Helpers" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<title>Index</title>
</asp:Content>

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

<ul id="leftColumn">
<% foreach (var item in Model.Groups) { %>
    <li <%= Html.Selected(item.Id, Model.SelectedGroup.Id) %>>
    <%= Ajax.ActionLink(item.Name, "Index", new { id = item.Id }, new AjaxOptions { UpdateTargetId = "divContactList"})%>
    </li>
<% } %>
</ul>
<div id="divContactList">
    <% Html.RenderPartial("ContactList", Model.SelectedGroup); %>
</div>

<div class="divContactList-bottom"> </div>
</asp:Content>

Es gibt zwei Dinge, die Sie bei der aktualisierten Ansicht in Listing 2 beachten sollten. Beachten Sie zunächst, dass der gesamte Inhalt, der in die Partielle verschoben wurde, durch einen Aufruf von Html.RenderPartial() ersetzt wird. Die Html.RenderPartial()-Methode wird aufgerufen, wenn die Indexansicht zum ersten Mal angefordert wird, um den anfänglichen Satz von Kontakten anzuzeigen.

Beachten Sie, dass html.ActionLink() zum Anzeigen von Kontaktgruppen durch einen Ajax.ActionLink() ersetzt wurde. Ajax.ActionLink() wird mit den folgenden Parametern aufgerufen:

<%= Ajax.ActionLink(item.Name, "Index", new { id = item.Id }, new AjaxOptions { UpdateTargetId = "divContactList"})%>

Der erste Parameter stellt den Text dar, der für den Link angezeigt werden soll, der zweite Parameter die Routenwerte und der dritte Parameter die Ajax-Optionen. In diesem Fall verwenden wir die Option UpdateTargetId Ajax, um auf das HTML-Div-Tag <> zu verweisen, das nach Abschluss der Ajax-Anforderung aktualisiert werden soll. Wir möchten das <div-Tag> mit der neuen Kontaktliste aktualisieren.

Die aktualisierte Index()-Methode des Kontaktcontrollers ist in Listing 3 enthalten.

Listing 3 – Controllers\ContactController.cs (Index-Methode)

public ActionResult Index(int? id)
{
    // Get selected group
    var selectedGroup = _service.GetGroup(id);
    if (selectedGroup == null)
        return RedirectToAction("Index", "Group");

    // Normal Request
    if (!Request.IsAjaxRequest())
    {
        var model = new IndexModel
        {
            Groups = _service.ListGroups(),
            SelectedGroup = selectedGroup
        };
        return View("Index", model);
    }

    // Ajax Request
    return PartialView("ContactList", selectedGroup);
}

Die aktualisierte Index()-Aktion gibt bedingt eine von zwei Dingen zurück. Wenn die Index()-Aktion von einer Ajax-Anforderung aufgerufen wird, gibt der Controller einen Teil zurück. Andernfalls gibt die Index()-Aktion eine gesamte Ansicht zurück.

Beachten Sie, dass die Index()-Aktion nicht so viele Daten zurückgeben muss, wenn sie von einer Ajax-Anforderung aufgerufen wird. Im Kontext einer normalen Anforderung gibt die Indexaktion eine Liste aller Kontaktgruppen und der ausgewählten Kontaktgruppe zurück. Im Kontext einer Ajax-Anforderung gibt die Index()-Aktion nur die ausgewählte Gruppe zurück. Ajax bedeutet weniger Arbeit auf Ihrem Datenbankserver.

Unsere geänderte Indexansicht funktioniert sowohl im Fall von Uplevel- als auch downlevel-Browsern. Wenn Sie auf eine Kontaktgruppe klicken und Ihr Browser JavaScript unterstützt, wird nur der Bereich der Ansicht aktualisiert, der die Kontaktliste enthält. Wenn Ihr Browser dagegen JavaScript nicht unterstützt, wird die gesamte Ansicht aktualisiert.

Unsere aktualisierte Indexansicht hat ein Problem. Wenn Sie auf eine Kontaktgruppe klicken, wird die ausgewählte Gruppe nicht hervorgehoben. Da die Liste der Gruppen außerhalb der Region angezeigt wird, die während einer Ajax-Anforderung aktualisiert wird, wird die rechte Gruppe nicht hervorgehoben. Dieses Problem wird im nächsten Abschnitt behoben.

Hinzufügen von jQuery-Animationseffekten

Wenn Sie auf einer Webseite auf einen Link klicken, können Sie normalerweise die Statusanzeige des Browsers verwenden, um zu erkennen, ob der Browser den aktualisierten Inhalt aktiv abruft oder nicht. Wenn Sie eine Ajax-Anforderung ausführen, zeigt die Statusanzeige des Browsers hingegen keinen Fortschritt an. Dies kann benutzer nervös machen. Woher wissen Sie, ob der Browser eingefroren ist?

Es gibt mehrere Möglichkeiten, wie Sie einem Benutzer mitteilen können, dass beim Ausführen einer Ajax-Anforderung Arbeit ausgeführt wird. Ein Ansatz besteht darin, eine einfache Animation anzuzeigen. Sie können beispielsweise einen Bereich ausblenden, wenn eine AJAX-Anforderung beginnt und in der Region ausgeblendet wird, wenn die Anforderung abgeschlossen ist.

Wir verwenden die jQuery-Bibliothek, die im Microsoft ASP.NET MVC-Framework enthalten ist, um die Animationseffekte zu erstellen. Die aktualisierte Indexansicht ist in Listing 4 enthalten.

Auflistung 4: Views\Contact\Index.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ContactManager.Models.ViewData.IndexModel>" %>
<%@ Import Namespace="Helpers" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<title>Index</title>
</asp:Content>

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

<script type="text/javascript">

    function beginContactList(args) {
        // Highlight selected group
        $('#leftColumn li').removeClass('selected');
        $(this).parent().addClass('selected');

        // Animate
        $('#divContactList').fadeOut('normal');
    }

    function successContactList() {
        // Animate
        $('#divContactList').fadeIn('normal');
    }

    function failureContactList() {
        alert("Could not retrieve contacts.");
    }

</script>

<ul id="leftColumn">
<% foreach (var item in Model.Groups) { %>
    <li <%= Html.Selected(item.Id, Model.SelectedGroup.Id) %>>
    <%= Ajax.ActionLink(item.Name, "Index", new { id = item.Id }, new AjaxOptions { UpdateTargetId = "divContactList", OnBegin = "beginContactList", OnSuccess = "successContactList", OnFailure = "failureContactList" })%>
    </li>
<% } %>
</ul>
<div id="divContactList">
    <% Html.RenderPartial("ContactList", Model.SelectedGroup); %>
</div>

<div class="divContactList-bottom"> </div>
</asp:Content>

Beachten Sie, dass die aktualisierte Indexansicht drei neue JavaScript-Funktionen enthält. Die ersten beiden Funktionen verwenden jQuery, um in der Kontaktliste auszublenden und einzublenden, wenn Sie auf eine neue Kontaktgruppe klicken. Die dritte Funktion zeigt eine Fehlermeldung an, wenn eine AJAX-Anforderung zu einem Fehler führt (z. B. Netzwerktimeout).

Die erste Funktion kümmert sich auch um das Hervorheben der ausgewählten Gruppe. Dem übergeordneten Element (dem LI-Element) des angeklickten Elements wird ein class=selected-Attribut hinzugefügt. Auch hier erleichtert jQuery die Auswahl des richtigen Elements und das Hinzufügen der CSS-Klasse.

Diese Skripts sind mit Hilfe des Ajax.ActionLink()-AjaxOptions-Parameters an die Gruppenlinks gebunden. Der aktualisierte Ajax.ActionLink()-Methodenaufruf sieht wie folgt aus:

<%= Ajax.ActionLink(item.Name, "Index", new { id = item.Id }, new AjaxOptions { UpdateTargetId = "divContactList", OnBegin = "beginContactList", OnSuccess = "successContactList", OnFailure = "failureContactList" })%>

Hinzufügen von Browserverlaufsunterstützung

Wenn Sie auf einen Link klicken, um eine Seite zu aktualisieren, wird ihr Browserverlauf normalerweise aktualisiert. Auf diese Weise können Sie auf die Schaltfläche Zurück im Browser klicken, um zum vorherigen Zustand der Seite zurückzukehren. Wenn Sie beispielsweise auf die Kontaktgruppe "Freunde" und dann auf die Kontaktgruppe "Unternehmen" klicken, können Sie auf die Schaltfläche Zurück im Browser klicken, um zurück zum Status der Seite zu navigieren, als die Kontaktgruppe "Freunde" ausgewählt wurde.

Leider wird beim Ausführen einer Ajax-Anforderung der Browserverlauf nicht automatisch aktualisiert. Wenn Sie auf eine Kontaktgruppe klicken und die Liste der übereinstimmenden Kontakte mit einer Ajax-Anforderung abgerufen wird, wird der Browserverlauf nicht aktualisiert. Sie können die Schaltfläche Zurück im Browser nicht verwenden, um nach der Auswahl einer neuen Kontaktgruppe zurück zu einer Kontaktgruppe zu navigieren.

Wenn Sie möchten, dass Benutzer nach der Ausführung von Ajax-Anforderungen die Schaltfläche Zurück im Browser verwenden können, müssen Sie etwas mehr Arbeit ausführen. Sie müssen die in der ASP.NET AJAX Framework integrierten Browserverlaufsverwaltungsfunktionen nutzen.

ASP.NET AJAX-Browserverlauf müssen Sie drei Dinge tun:

  1. Aktivieren Sie den Browserverlauf, indem Sie die enableBrowserHistory-Eigenschaft auf true festlegen.
  2. Speichern Sie Verlaufspunkte, wenn sich der Zustand einer Ansicht ändert, indem Sie die addHistoryPoint()-Methode aufrufen.
  3. Rekonstruieren Sie den Zustand der Ansicht, wenn das Navigationsereignis ausgelöst wird.

Die aktualisierte Indexansicht ist in Listing 5 enthalten.

Auflistung 5 : Views\Contact\Index.aspx

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<ContactManager.Models.ViewData.IndexModel>" %>
<%@ Import Namespace="Helpers" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<title>Index</title>
</asp:Content>

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

<script type="text/javascript">

    var _currentGroupId = -1;

    Sys.Application.add_init(pageInit);

    function pageInit() {
        // Enable history
        Sys.Application.set_enableHistory(true);

        // Add Handler for history
        Sys.Application.add_navigate(navigate);
    }

    function navigate(sender, e) {
        // Get groupId from address bar
        var groupId = e.get_state().groupId;

        // If groupId != currentGroupId then navigate
        if (groupId != _currentGroupId) {
            _currentGroupId = groupId;
            $("#divContactList").load("/Contact/Index/" + groupId);
            selectGroup(groupId);
        }
    }

    function selectGroup(groupId) {
        $('#leftColumn li').removeClass('selected');
        if (groupId)
            $('a[groupid=' + groupId + ']').parent().addClass('selected');
        else
            $('#leftColumn li:first').addClass('selected');
    }

    function beginContactList(args) {
        // Highlight selected group
        _currentGroupId = this.getAttribute("groupid");
        selectGroup(_currentGroupId);

        // Add history point
        Sys.Application.addHistoryPoint({ "groupId": _currentGroupId });

        // Animate
        $('#divContactList').fadeOut('normal');
    }

    function successContactList() {
        // Animate
        $('#divContactList').fadeIn('normal');
    }

    function failureContactList() {
        alert("Could not retrieve contacts.");
    }

</script>

<ul id="leftColumn">
<% foreach (var item in Model.Groups) { %>
    <li <%= Html.Selected(item.Id, Model.SelectedGroup.Id) %>>
    <%= Ajax.ActionLink(item.Name, "Index", new { id = item.Id }, new AjaxOptions { UpdateTargetId = "divContactList", OnBegin = "beginContactList", OnSuccess = "successContactList", OnFailure = "failureContactList" }, new { groupid = item.Id })%>
    </li>
<% } %>
</ul>
<div id="divContactList">
    <% Html.RenderPartial("ContactList", Model.SelectedGroup); %>
</div>

<div class="divContactList-bottom"> </div>
</asp:Content>

In Listing 5 ist der Browserverlauf in der pageInit()-Funktion aktiviert. Die pageInit()-Funktion wird auch verwendet, um den Ereignishandler für das navigate-Ereignis einzurichten. Das Navigationsereignis wird immer dann ausgelöst, wenn die Schaltfläche Vorwärts oder Zurück im Browser bewirkt, dass sich der Zustand der Seite ändert.

Die beginContactList()-Methode wird aufgerufen, wenn Sie auf eine Kontaktgruppe klicken. Diese Methode erstellt einen neuen Verlaufspunkt, indem die addHistoryPoint()-Methode aufgerufen wird. Die ID der angeklickten Kontaktgruppe wird dem Verlauf hinzugefügt.

Die Gruppen-ID wird aus einem expando-Attribut im Kontaktgruppenlink abgerufen. Der Link wird mit dem folgenden Aufruf von Ajax.ActionLink() gerendert.

<%= Ajax.ActionLink(item.Name, "Index", new { id = item.Id }, new AjaxOptions { UpdateTargetId = "divContactList", OnBegin = "beginContactList", OnSuccess = "successContactList", OnFailure = "failureContactList" }, new {groupid=item.Id})%>

Der letzte Parameter, der an ajax.ActionLink() übergeben wurde, fügt dem Link ein Expando-Attribut namens groupid hinzu (für XHTML-Kompatibilität in Kleinbuchstaben).

Wenn ein Benutzer auf die Schaltfläche Zurück oder Vorwärts im Browser klickt, wird das Navigate-Ereignis ausgelöst, und die navigate()-Methode wird aufgerufen. Diese Methode aktualisiert die auf der Seite angezeigten Kontakte so, dass sie dem Zustand der Seite entsprechen, der dem an die navigate-Methode übergebenen Browserverlaufspunkt entspricht.

Ausführen von Ajax-Löschvorgängen

Derzeit müssen Sie zum Löschen eines Kontakts auf den Link Löschen klicken und dann auf die Schaltfläche Löschen klicken, die auf der Löschbestätigungsseite angezeigt wird (siehe Abbildung 2). Dies scheint viele Seitenanforderungen zu sein, um etwas Einfaches wie das Löschen eines Datenbankdatensatzes zu tun.

Die Löschbestätigungsseite

Abbildung 02: Die Löschbestätigungsseite (Klicken Sie hier, um das Bild in voller Größe anzuzeigen)

Es ist verlockend, die Löschbestätigungsseite zu überspringen und einen Kontakt direkt aus der Indexansicht zu löschen. Sie sollten diese Versuchung vermeiden, da dieser Ansatz Ihre Anwendung zu Sicherheitslücken führt. Im Allgemeinen möchten Sie keinen HTTP GET-Vorgang ausführen, wenn Sie eine Aktion aufrufen, die den Zustand Ihrer Webanwendung ändert. Wenn Sie einen Löschvorgang ausführen, möchten Sie einen HTTP POST-Vorgang oder besser noch einen HTTP DELETE-Vorgang ausführen.

Der Link Löschen ist in der ContactList-Partielle enthalten. Eine aktualisierte Version der ContactList-Partielle ist in Listing 6 enthalten.

Auflistung 6 : Views\Contact\ContactList.ascx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ContactManager.Models.Group>" %>
<%@ Import Namespace="Helpers" %>
<table class="data-table" cellpadding="0" cellspacing="0">
    <thead>
        <tr>
            <th class="actions edit">
                Edit
            </th>
            <th class="actions delete">
                Delete
            </th>
            <th>
                Name
            </th>
            <th>
                Phone
            </th>
            <th>
                Email
            </th>
        </tr>
    </thead>
    <tbody>
        <% foreach (var item in Model.Contacts)
           { %>
        <tr>
            <td class="actions edit">
                <a href='<%= Url.Action("Edit", new {id=item.Id}) %>'><img src="../../Content/Edit.png" alt="Edit" /></a>
            </td>
            <td class="actions delete">
            <%= Ajax.ImageActionLink("../../Content/Delete.png", "Delete", "Delete", new { id = item.Id }, new AjaxOptions { Confirm = "Delete contact?", HttpMethod = "Delete", UpdateTargetId = "divContactList" })%> 
            </td>
            <th>
                <%= Html.Encode(item.FirstName) %>
                <%= Html.Encode(item.LastName) %>
            </th>
            <td>
                <%= Html.Encode(item.Phone) %>
            </td>
            <td>
                <%= Html.Encode(item.Email) %>
            </td>
        </tr>
        <% } %>
    </tbody>
</table>

Der Delete-Link wird mit dem folgenden Aufruf der Ajax.ImageActionLink()-Methode gerendert:

<%= Ajax.ImageActionLink("../../Content/Delete.png", "Delete", "Delete", new { id = item.Id }, new AjaxOptions { Confirm = "Delete contact?", HttpMethod = "Delete", UpdateTargetId = "divContactList" })%>

Hinweis

Ajax.ImageActionLink() ist kein Standardbestandteil des ASP.NET MVC-Frameworks. Ajax.ImageActionLink() ist eine benutzerdefinierte Hilfsmethode, die im Contact Manager-Projekt enthalten ist.

Der AjaxOptions-Parameter verfügt über zwei Eigenschaften. Zunächst wird die Confirm-Eigenschaft verwendet, um ein Popup-JavaScript-Bestätigungsdialogfeld anzuzeigen. Zweitens wird die HttpMethod-Eigenschaft verwendet, um einen HTTP DELETE-Vorgang auszuführen.

Listing 7 enthält eine neue AjaxDelete()-Aktion, die dem Kontaktcontroller hinzugefügt wurde.

Auflistung 7 : Controllers\ContactController.cs (AjaxDelete)

[AcceptVerbs(HttpVerbs.Delete)]
[ActionName("Delete")]
public ActionResult AjaxDelete(int id)
{
    // Get contact and group
    var contactToDelete = _service.GetContact(id);
    var selectedGroup = _service.GetGroup(contactToDelete.Group.Id);

    // Delete from database
    _service.DeleteContact(contactToDelete);

    // Return Contact List
    return PartialView("ContactList", selectedGroup);
}

Die AjaxDelete()-Aktion wird mit einem AcceptVerbs-Attribut ergänzt. Dieses Attribut verhindert, dass die Aktion aufgerufen wird, außer durch einen HTTP-Vorgang außer einem HTTP-DELETE-Vorgang. Insbesondere können Sie diese Aktion nicht mit einem HTTP GET aufrufen.

Nachdem Sie den Datenbankdatensatz gelöscht haben, müssen Sie die aktualisierte Liste der Kontakte anzeigen, die den gelöschten Datensatz nicht enthält. Die AjaxDelete()-Methode gibt die ContactList-Partielle und die aktualisierte Kontaktliste zurück.

Zusammenfassung

In dieser Iteration haben wir ajax-Funktionalität zu unserer Contact Manager-Anwendung hinzugefügt. Wir haben Ajax verwendet, um die Reaktionsfähigkeit und Leistung unserer Anwendung zu verbessern.

Zunächst haben wir die Indexansicht umgestaltet, sodass durch Klicken auf eine Kontaktgruppe nicht die gesamte Ansicht aktualisiert wird. Wenn Sie stattdessen auf eine Kontaktgruppe klicken, wird nur die Liste der Kontakte aktualisiert.

Als Nächstes haben wir jQuery-Animationseffekte verwendet, um in der Kontaktliste auszublenden und zu verblassen. Das Hinzufügen von Animationen zu einer AJAX-Anwendung kann verwendet werden, um Benutzern der Anwendung das Äquivalent einer Browserstatusleiste bereitzustellen.

Außerdem haben wir unserer Ajax-Anwendung Browserverlaufsunterstützung hinzugefügt. Wir haben Benutzern ermöglicht, auf die Schaltflächen "Zurück" und "Vorwärts" im Browser zu klicken, um den Status der Indexansicht zu ändern.

Schließlich haben wir einen Löschlink erstellt, der HTTP DELETE-Vorgänge unterstützt. Durch die Durchführung von Ajax-Löschvorgängen können Benutzer Datenbankdatensätze löschen, ohne dass der Benutzer eine zusätzliche Löschbestätigungsseite anfordern muss.