Iteracja 7 — Dodawanie funkcji Ajax (C#)

autor: Microsoft

Pobierz kod

W siódmej iteracji poprawiamy czas odpowiedzi i wydajność naszej aplikacji, dodając obsługę Ajax.

Tworzenie aplikacji MVC do zarządzania kontaktami ASP.NET (C#)

W tej serii samouczków utworzymy całą aplikację do zarządzania kontaktami od początku do końca. Aplikacja Contact Manager umożliwia przechowywanie informacji kontaktowych — nazw, numerów telefonów i adresów e-mail — dla listy osób.

Tworzymy aplikację za pośrednictwem wielu iteracji. Wraz z każdą iteracją stopniowo ulepszamy aplikację. Celem tego podejścia iteracji wielokrotnej jest umożliwienie zrozumienia przyczyny każdej zmiany.

  • Iteracja #1 — tworzenie aplikacji. W pierwszej iteracji tworzymy Menedżera kontaktów w najprostszy możliwy sposób. Dodajemy obsługę podstawowych operacji bazy danych: tworzenie, odczyt, aktualizowanie i usuwanie (CRUD).

  • Iteracja #2 — sprawia, że aplikacja wygląda ładnie. W tej iteracji poprawiamy wygląd aplikacji, modyfikując domyślną stronę wzorcową widoku MVC ASP.NET oraz kaskadowy arkusz stylów.

  • Iteracja 3 — dodawanie walidacji formularza. W trzeciej iteracji dodamy podstawową walidację formularza. Uniemożliwiamy użytkownikom przesyłanie formularza bez wypełniania wymaganych pól formularza. Weryfikujemy również adresy e-mail i numery telefonów.

  • Iteracja #4 — luźno sprzężenie aplikacji. W tej czwartej iteracji korzystamy z kilku wzorców projektowych oprogramowania, aby ułatwić konserwację i modyfikowanie aplikacji Contact Manager. Na przykład refaktoryzujemy naszą aplikację, aby używać wzorca repozytorium i wzorca wstrzykiwania zależności.

  • Iteracja 5 — tworzenie testów jednostkowych. W piątej iteracji ułatwiamy konserwację i modyfikowanie aplikacji przez dodawanie testów jednostkowych. Wyśmiewamy nasze klasy modelu danych i tworzymy testy jednostkowe dla naszych kontrolerów i logiki walidacji.

  • Iteracja 6 — używanie programowania opartego na testach. W tej szóstej iteracji do naszej aplikacji dodamy nowe funkcje, pisząc najpierw testy jednostkowe i pisząc kod względem testów jednostkowych. W tej iteracji dodajemy grupy kontaktów.

  • Iteracja #7 — dodawanie funkcji Ajax. W siódmej iteracji poprawiamy czas odpowiedzi i wydajność naszej aplikacji, dodając obsługę Ajax.

Ta iteracja

W tej iteracji aplikacji Contact Manager refaktoryzujemy naszą aplikację, aby korzystać z technologii Ajax. Korzystając z technologii Ajax, sprawiamy, że nasza aplikacja będzie bardziej elastyczna. Możemy uniknąć renderowania całej strony, gdy musimy zaktualizować tylko określony region na stronie.

Refaktoryzujemy nasz widok Indeks, aby nie trzeba było ponownie redystować całej strony za każdym razem, gdy ktoś wybierze nową grupę kontaktów. Zamiast tego, gdy ktoś kliknie grupę kontaktów, po prostu zaktualizujemy listę kontaktów i pozostawimy pozostałą część strony.

Zmienimy również sposób działania linku usuwania. Zamiast wyświetlać oddzielną stronę potwierdzenia, zostanie wyświetlone okno dialogowe potwierdzenia języka JavaScript. Jeśli potwierdzisz, że chcesz usunąć kontakt, na serwerze jest wykonywana operacja USUWANIA PROTOKOŁU HTTP w celu usunięcia rekordu kontaktu z bazy danych.

Ponadto skorzystamy z funkcji jQuery, aby dodać efekty animacji do widoku indeksu. Gdy nowa lista kontaktów zostanie pobrana z serwera, zostanie wyświetlona animacja.

Na koniec skorzystamy z obsługi platformy AJAX ASP.NET do zarządzania historią przeglądarki. Utworzymy punkty historii za każdym razem, gdy wykonamy wywołanie Ajax, aby zaktualizować listę kontaktów. Dzięki temu przyciski do tyłu i do przodu będą działać w przeglądarce.

Dlaczego warto używać Ajax?

Korzystanie z Ajax ma wiele korzyści. Najpierw dodanie funkcji Ajax do aplikacji powoduje lepsze środowisko użytkownika. W normalnej aplikacji internetowej cała strona musi zostać opublikowana z powrotem na serwerze za każdym razem, gdy użytkownik wykonuje akcję. Za każdym razem, gdy wykonujesz akcję, przeglądarka zostanie zablokowana, a użytkownik musi poczekać, aż cała strona zostanie pobrana i ponownie odtworzona.

Byłoby to niedopuszczalne środowisko w przypadku aplikacji klasycznej. Jednak tradycyjnie używaliśmy tego złego środowiska użytkownika w przypadku aplikacji internetowej, ponieważ nie wiedzieliśmy, że możemy zrobić lepiej. Myśleliśmy, że jest to ograniczenie aplikacji internetowych, gdy w rzeczywistości było to tylko ograniczenie naszej wyobraźni.

W aplikacji Ajax nie trzeba zatrzymywać środowiska użytkownika tylko po to, aby zaktualizować stronę. Zamiast tego możesz wykonać żądanie asynchroniczne w tle, aby zaktualizować stronę. Nie wymuszasz, aby użytkownik czekał, gdy część strony zostanie zaktualizowana.

Korzystając z technologii Ajax, możesz również zwiększyć wydajność aplikacji. Zastanów się, jak działa teraz aplikacja Contact Manager bez funkcji Ajax. Po kliknięciu grupy kontaktów cały widok indeksu musi zostać ponownie odtworzona. Lista kontaktów i lista grup kontaktów musi zostać pobrana z serwera bazy danych. Wszystkie te dane muszą być przekazywane przez sieć z serwera internetowego do przeglądarki internetowej.

Po dodaniu funkcji Ajax do naszej aplikacji możemy jednak uniknąć ponownego tworzenia całej strony, gdy użytkownik kliknie grupę kontaktów. Nie musimy już pobierać grup kontaktów z bazy danych. Nie musimy również wypychać całego widoku indeksu przez sieć. Korzystając z technologii Ajax, zmniejszamy ilość pracy wymaganej przez serwer bazy danych i zmniejszamy ilość ruchu sieciowego wymaganego przez naszą aplikację.

Nie bój się Ajax

Niektórzy deweloperzy unikają korzystania z technologii Ajax, ponieważ martwią się o przeglądarki w dół. Chce się upewnić, że ich aplikacje internetowe będą nadal działać po korzystaniu z przeglądarki, która nie obsługuje języka JavaScript. Ponieważ Ajax zależy od języka JavaScript, niektórzy deweloperzy unikają korzystania z Ajax.

Jednak jeśli uważasz na sposób implementacji Ajax, możesz tworzyć aplikacje, które współpracują zarówno z przeglądarkami na poziomach, jak i w dół. Nasza aplikacja Contact Manager będzie działać z przeglądarkami, które obsługują język JavaScript i przeglądarki, które nie są obsługiwane.

Jeśli używasz aplikacji Contact Manager z przeglądarką, która obsługuje język JavaScript, będziesz mieć lepsze środowisko użytkownika. Na przykład po kliknięciu grupy kontaktów zostanie zaktualizowany tylko region strony wyświetlający kontakty.

Jeśli z drugiej strony używasz aplikacji Contact Manager z przeglądarką, która nie obsługuje języka JavaScript (lub ma wyłączony język JavaScript), wówczas środowisko użytkownika będzie nieco mniej pożądane. Na przykład po kliknięciu grupy kontaktów cały widok Indeks musi zostać opublikowany z powrotem w przeglądarce, aby wyświetlić pasującą listę kontaktów.

Dodawanie wymaganych plików JavaScript

Musimy użyć trzech plików JavaScript, aby dodać funkcje Ajax do naszej aplikacji. Wszystkie trzy z tych plików znajdują się w folderze Scripts nowego ASP.NET aplikacji MVC.

Jeśli planujesz używać Ajax na wielu stronach w aplikacji, warto uwzględnić wymagane pliki JavaScript na stronie wzorcowej widoku aplikacji. Dzięki temu pliki JavaScript zostaną automatycznie uwzględnione we wszystkich stronach aplikacji.

Dodaj następujący kod JavaScript w tagu <head> strony wzorcowej widoku:

<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>

Refaktoryzacja widoku indeksu w celu korzystania z Ajax

Zacznijmy od zmodyfikowania widoku Indeks, aby kliknięcie grupy kontaktów zaktualizowało tylko region widoku, w którym są wyświetlane kontakty. Czerwone pole na rysunku 1 zawiera region, który chcemy zaktualizować.

Aktualizowanie tylko kontaktów

Rysunek 01. Aktualizowanie tylko kontaktów (kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Pierwszym krokiem jest oddzielenie części widoku, którą chcemy zaktualizować asynchronicznie do oddzielnej części (wyświetl kontrolkę użytkownika). Sekcja widoku Indeks wyświetlający tabelę kontaktów została przeniesiona do częściowej listy 1.

Lista 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>

Zwróć uwagę, że część z listy 1 ma inny model niż widok Indeks. Atrybut Dziedziczy w <dyrektywie %@ Page %> określa, że częściowe dziedziczy z klasy ViewUserControl<Group>.

Zaktualizowany widok indeksu znajduje się na liście 2.

Lista 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>

Istnieją dwie rzeczy, które należy zwrócić uwagę na zaktualizowany widok na liście 2. Najpierw zwróć uwagę, że cała zawartość przeniesiona do części jest zastępowana wywołaniem metody Html.RenderPartial(). Metoda Html.RenderPartial() jest wywoływana, gdy widok Indeks jest najpierw żądany w celu wyświetlenia początkowego zestawu kontaktów.

Po drugie zwróć uwagę, że element Html.ActionLink() używany do wyświetlania grup kontaktów został zastąpiony elementem Ajax.ActionLink(). Element Ajax.ActionLink() jest wywoływany z następującymi parametrami:

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

Pierwszy parametr reprezentuje tekst wyświetlany dla łącza, drugi parametr reprezentuje wartości trasy, a trzeci parametr reprezentuje opcje Ajax. W tym przypadku używamy opcji UpdateTargetId Ajax, aby wskazać tag div> HTML<, który chcemy zaktualizować po zakończeniu żądania Ajax. Chcemy zaktualizować <tag div> przy użyciu nowej listy kontaktów.

Zaktualizowana metoda Index() kontrolera kontaktów znajduje się na liście 3.

Lista 3 — Controllers\ContactController.cs (metoda indeksu)

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);
}

Zaktualizowana akcja Index() warunkowo zwraca jedną z dwóch rzeczy. Jeśli akcja Index() jest wywoływana przez żądanie Ajax, kontroler zwraca częściowe. W przeciwnym razie akcja Index() zwraca cały widok.

Zwróć uwagę, że akcja Index() nie musi zwracać tyle danych po wywołaniu żądania Ajax. W kontekście normalnego żądania akcja Indeks zwraca listę wszystkich grup kontaktów i wybranej grupy kontaktów. W kontekście żądania Ajax akcja Index() zwraca tylko wybraną grupę. Ajax oznacza mniej pracy na serwerze bazy danych.

Nasz zmodyfikowany widok indeksu działa zarówno w przypadku przeglądarek w górę, jak i w dół. Jeśli klikniesz grupę kontaktów, a przeglądarka obsługuje język JavaScript, zostanie zaktualizowany tylko region widoku, który zawiera listę kontaktów. Jeśli z drugiej strony przeglądarka nie obsługuje języka JavaScript, cały widok zostanie zaktualizowany.

Nasz zaktualizowany widok indeksu ma jeden problem. Po kliknięciu grupy kontaktów wybrana grupa nie zostanie wyróżniona. Ponieważ lista grup jest wyświetlana poza regionem, który jest aktualizowany podczas żądania Ajax, właściwa grupa nie zostanie wyróżniona. Rozwiążemy ten problem w następnej sekcji.

Dodawanie efektów animacji jQuery

Zwykle po kliknięciu linku na stronie internetowej można użyć paska postępu przeglądarki, aby wykryć, czy przeglądarka aktywnie pobiera zaktualizowaną zawartość. Natomiast podczas wykonywania żądania Ajax pasek postępu przeglądarki nie pokazuje żadnego postępu. Może to sprawić, że użytkownicy będą zdenerwowani. Jak sprawdzić, czy przeglądarka została zamrożona?

Istnieje kilka sposobów wskazywania użytkownikowi, że praca jest wykonywana podczas wykonywania żądania Ajax. Jednym z podejść jest wyświetlenie prostej animacji. Na przykład możesz zniknąć region po rozpoczęciu żądania Ajax i zanikaniu w regionie po zakończeniu żądania.

Użyjemy biblioteki jQuery dołączonej do platformy Microsoft ASP.NET MVC, aby utworzyć efekty animacji. Zaktualizowany widok indeksu znajduje się na liście 4.

Lista 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>

Zwróć uwagę, że zaktualizowany widok indeksu zawiera trzy nowe funkcje języka JavaScript. Pierwsze dwie funkcje używają biblioteki jQuery do zanikania i zanikania na liście kontaktów po kliknięciu nowej grupy kontaktów. Trzecia funkcja wyświetla komunikat o błędzie, gdy żądanie AJAX powoduje błąd (na przykład limit czasu sieci).

Pierwsza funkcja zajmuje się również wyróżnianie wybranej grupy. Klasa = wybrany atrybut jest dodawany do elementu nadrzędnego (elementu LI) klikniętego elementu. Ponownie jQuery ułatwia wybranie odpowiedniego elementu i dodanie klasy CSS.

Te skrypty są powiązane z linkami grup za pomocą parametru Ajax.ActionLink() AjaxOptions. Zaktualizowane wywołanie metody Ajax.ActionLink() wygląda następująco:

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

Dodawanie obsługi historii przeglądarki

Zwykle po kliknięciu linku w celu zaktualizowania strony historia przeglądarki zostanie zaktualizowana. W ten sposób możesz kliknąć przycisk Wstecz przeglądarki, aby wrócić w czasie do poprzedniego stanu strony. Jeśli na przykład klikniesz grupę Kontakty znajomych, a następnie klikniesz grupę Kontakty biznesowe, możesz kliknąć przycisk Wstecz w przeglądarce, aby wrócić do stanu strony po wybraniu grupy kontaktów Znajomi.

Niestety wykonanie żądania Ajax nie powoduje automatycznej aktualizacji historii przeglądarki. Jeśli klikniesz grupę kontaktów, a lista pasujących kontaktów zostanie pobrana z żądaniem Ajax, historia przeglądarki nie zostanie zaktualizowana. Nie można użyć przycisku Wstecz przeglądarki, aby wrócić do grupy kontaktów po wybraniu nowej grupy kontaktów.

Jeśli chcesz, aby użytkownicy mogli korzystać z przycisku Wstecz przeglądarki po wykonaniu żądań Ajax, musisz wykonać nieco więcej pracy. Musisz skorzystać z funkcji zarządzania historią przeglądarki wbudowanych w platformę ASP.NET AJAX Framework.

ASP.NET historii przeglądarki AJAX należy wykonać trzy czynności:

  1. Włącz historię przeglądarki, ustawiając właściwość enableBrowserHistory na true.
  2. Zapisz punkty historii, gdy stan widoku ulegnie zmianie, wywołując metodę addHistoryPoint().
  3. Zrekonstruuj stan widoku po wystąpieniu zdarzenia nawigacji.

Zaktualizowany widok indeksu znajduje się na liście 5.

Lista 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>

Na liście 5 funkcja Historia przeglądarki jest włączona w funkcji pageInit(). Funkcja pageInit() służy również do konfigurowania programu obsługi zdarzeń dla zdarzenia nawigacji. Zdarzenie nawigacji jest wywoływane za każdym razem, gdy przycisk Prześlij dalej lub Wstecz w przeglądarce powoduje zmianę stanu strony.

Metoda beginContactList() jest wywoływana po kliknięciu grupy kontaktów. Ta metoda tworzy nowy punkt historii, wywołując metodę addHistoryPoint(). Identyfikator klikniętej grupy kontaktów jest dodawany do historii.

Identyfikator grupy jest pobierany z atrybutu expando w linku grupy kontaktów. Link jest renderowany za pomocą następującego wywołania metody Ajax.ActionLink().

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

Ostatni parametr przekazany do elementu Ajax.ActionLink() dodaje do linku atrybut expando o nazwie groupid (małe litery w celu zachowania zgodności kodu XHTML).

Gdy użytkownik naciśnie przycisk Wstecz lub Prześlij dalej w przeglądarce, zostanie zgłoszone zdarzenie nawigacji i wywołana jest metoda navigate(). Ta metoda aktualizuje kontakty wyświetlane na stronie, aby odpowiadały stanowi strony odpowiadającej punktowi historii przeglądarki przekazanemu do metody navigate.

Wykonywanie operacji usuwania AJAX

Obecnie, aby usunąć kontakt, należy kliknąć link Usuń, a następnie kliknąć przycisk Usuń wyświetlony na stronie potwierdzenia usuwania (zobacz Rysunek 2). Wygląda na to, że wiele żądań stron, aby wykonać coś prostego, takiego jak usunięcie rekordu bazy danych.

Strona potwierdzenia usunięcia

Rysunek 02. Strona potwierdzenia usuwania (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Kuszące jest pominięcie strony potwierdzenia usunięcia i usunięcie kontaktu bezpośrednio z widoku Indeks. Należy unikać tej pokusy, ponieważ takie podejście otwiera aplikację do luk w zabezpieczeniach. Ogólnie rzecz biorąc, nie chcesz wykonywać operacji HTTP GET podczas wywoływania akcji modyfikującej stan aplikacji internetowej. Podczas usuwania chcesz wykonać operację HTTP POST lub jeszcze lepiej, operację HTTP DELETE.

Link Usuń znajduje się w częściowej listy ContactList. Zaktualizowana wersja częściowej listy ContactList znajduje się na liście 6.

Lista 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>

Link Delete jest renderowany za pomocą następującego wywołania metody Ajax.ImageActionLink():

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

Uwaga

Ajax.ImageActionLink() nie jest standardową częścią platformy ASP.NET MVC. Ajax.ImageActionLink() to niestandardowe metody pomocnicze zawarte w projekcie Contact Manager.

Parametr AjaxOptions ma dwie właściwości. Najpierw właściwość Confirm służy do wyświetlania wyskakującego okna dialogowego potwierdzenia języka JavaScript. Po drugie właściwość HttpMethod służy do wykonywania operacji HTTP DELETE.

Lista 7 zawiera nową akcję AjaxDelete(), która została dodana do kontrolera kontaktów.

Lista 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);
}

Akcja AjaxDelete() jest ozdobiona atrybutem AcceptVerbs. Ten atrybut uniemożliwia wywoływanie akcji z wyjątkiem dowolnej operacji HTTP innej niż operacja HTTP DELETE. W szczególności nie można wywołać tej akcji za pomocą żądania HTTP GET.

Po usunięciu rekordu bazy danych należy wyświetlić zaktualizowaną listę kontaktów, które nie zawierają usuniętego rekordu. Metoda AjaxDelete() zwraca częściową listę ContactList i zaktualizowaną listę kontaktów.

Podsumowanie

W tej iteracji dodaliśmy funkcję Ajax do naszej aplikacji Contact Manager. Użyliśmy technologii Ajax, aby poprawić czas reakcji i wydajność naszej aplikacji.

Najpierw refaktoryzowaliśmy widok Indeks, aby kliknięcie grupy kontaktów nie zaktualizowało całego widoku. Zamiast tego kliknięcie grupy kontaktów aktualizuje tylko listę kontaktów.

Następnie użyliśmy efektów animacji jQuery, aby zniknąć i zniknąć na liście kontaktów. Dodanie animacji do aplikacji Ajax może służyć do udostępniania użytkownikom aplikacji odpowiednika paska postępu przeglądarki.

Dodaliśmy również obsługę historii przeglądarki do naszej aplikacji Ajax. Umożliwiliśmy użytkownikom klikanie przycisków Wstecz i Prześlij dalej w przeglądarce, aby zmienić stan widoku Indeks.

Na koniec utworzyliśmy link usuwania, który obsługuje operacje USUWANIA HTTP. Wykonując operacje usuwania Ajax, umożliwiamy użytkownikom usuwanie rekordów bazy danych bez konieczności żądania dodatkowej strony potwierdzenia usunięcia przez użytkownika.