Використання AJAX в ASP.NET

Історія розвитку web-додатків


Розглядаючи ту або іншу нову технологію перш за все необхідно розібратися для чого ця сама технологія необхідна і що саме вона дозволяє (або полегшує) робити, що не дозволяють робити інші технології. Щоб більш наочно зрозуміти, які передумови були до появи AJAX, можна розглянути процес еволюційного розвитку web-сайтів.


На самій зорі розвитку інтернет сайти представляли собою набір простих статичних сторінок – користувач запитував ресурс у сервера і сервер повертав статичну сторінку. Ця сторінка була простий HTML текст і зберігалася як текстовий файл на сервері. Дана сторінка поставлялася користувачеві as is і, крім того, не мала жодних клієнтських скриптів.


CGI


Перша спроба зробити сторінки динамічнішими був Common Gateway Interface (CGI). CGI дозволяв розробнику створювати виконувані програми, які генерували сторінку, що дозволяло приймати параметри від користувача. З урахуванням цих параметрів можна було генерувати унікальну сторінку. За великим рахунком, цей підхід використовується і зараз у тому ж ASP.NET, PHP і т.д.


JavaScript


Генерація сторінок на серверній стороні це звичайно добре, але це змушувало при кожному, навіть самому незначному дії користувача, робити запит до сервера з перевантаженням всієї сторінки. Щоб не перевантажувати всю сторінку у випадках, коли участь сервера абсолютно не потрібно, стали використовуватися клієнтські скрипти.


Аплети і Flash


У випадку, якщо запит до сервера все ж необхідний і одними клієнтськими скриптами не обійтися – розробники в web-сторінках стали використовувати т.зв. аплети а також flash.


Аплети вперше були використані в 1995 році, коли Sun представила світу на загальний огляд свою нову платформу з новою мовою – JAVA. По суті аплети представляли собою програми, написані на JAVA і які могли запускатися в броузері як окремі додатки. Для того, щоб ця програма, написана на невідомому для броузера мові JAVA, могла бути запущена всередині броузера, необхідно було встановити JVM (Java Virtual Machine) – середовище для виконання програм JAVA. І хоча даний підхід звучить дуже заманливо – він мав безліч недоліків, перш за все це проблеми безпеки (не кожен користувач, подорожуючи по інтернет, дозволить запускати на своєму комп'ютері програми незрозумілого походження) та необхідність громозкой VM. Незважаючи на те, що крім спілкування з сервером аплети і флеш також дозволяли реалізувати можливості, недоступні JavaScript (скажімо, більш високі вимоги до графіку) – ті складності не дали апплетам прижитися настільки, щоб остаточно вирішити проблеми із запитами до сервера.


DHTML


Dynamic HTML об'єднав в собі HTML, каскадні таблиці стилів (CSS) і JavaScript. Також до всього цього набору додався DOM – об'єктна модель броузера. Вся ця суміш дозволяла (і дозволяє) успішно створювати дуже красиві, зручні і функціональні сторінки «на льоту». Але знову ж таки, у випадку, якщо потрібно виконати запит до сервера – доводиться перевантажувати весь документ.


AJAX


Вирішення цієї проблеми прийшло з появою нової технології, яка в 2004 році була названа AJAX (Asynchronous JavaScript + XML). Дана технологія побудована на принципі виконання запиту до сервера з використанням JavaScript і отримання результату знову ж таки, за допомогою JavaScript, що дозволяє уникнути перевантаження сторінки і отже має кілька незаперечних переваг:



  1. На сервер відправляються не всі елементи сторінки (точніше не їх значення), а тільки ті мінімальні дані, які необхідні для виконання того чи іншого запиту і у відповідь приймається не вся сторінка, а тільки необхідні дані, що дозволяє зменшити трафік в десятки (а іноді і в сотні) разів.
  2. Не відбувається перевантаження сторінки в броузері і в користувача створюється враження, що все відбувається на його комп'ютері.

Про цю технології і піде далі мова.


Об'єктна модель броузера.


Якщо ви мене запитаєте на чому заснований принцип роботи технології AJAX, то я вам напевно відповім: «завдяки об'єктної моделі броузера». Що ж це за така об'єктна модель броузера (DOM)?


Document Object Model (DOM) – це специфікація, стандартизована W3C комітетом, яка є кроссплатформенной і описує виклики і опису, що стосуються дій з самим документом, його структурою, HTML, XML і стилями. Як випливає з назви, основою специфікації DOM є об'єкти.


Об'єкт XMLHttpRequest


Цей об'єкт з'явився вперше в Internet Explorer 5.0 і був реалізований як ActiveX компонент. Важливо зауважити, що цей об'єкт не є стандартом W3C, хоча багато що з його функціональності описано в специфікації «The DOM Level 3 Load and Save Specification». З цієї причини його поведінка може трохи відрізнятися в різних броузерах. Але у всіх броузерах він виконує одну і ту ж функціональність – він вміє посилати запити до сервера і отримувати від нього відповіді. Як вже говорилося вище, даний об'єкт не стандартизований і створення його instance може відрізнятися в різних версіях, тому для «надійного» його створення краще використовувати код, який об'єднує в собі створення instance в декількох броузерах подібно коду нижче:

 var xmlHttp;
function createXMLHttpRequest()
{
if (window.ActiveXObject)
{
xmlHttp = new ActiveXObject(“Microsoft.XMLHTTP”);
}
else if (window.XMLHttpRequest)
{
xmlHttp = new XMLHttpRequest();
}
}

XMLHttpRequest має ряд «стандартних» (стандартних у лапках тому що як писалося вище, даний об'єкт не стандартизований для всіх броузерів) властивостей і методів, які дозволяють даному об'єкту посилати запит, перевіряти стан запиту і отримувати результат виконання запиту від віддаленого сервера. Ці властивості і методи ми розглянемо в наступних двох таблицях.


У таблиці 1 представлені «стандартні» властивості XMLHttpRequest

























Метод



Опис


abort()


Перериває поточний запит


getAllResponseHeaders()


Повертає всі заголовки Response у вигляді ключ / значення


getResponseHeader(header)


Повертає значення певного заголовка


open(method, url, asynch, username, password)


Встановлює стан запиту до сервера. Перший параметр вказує метод запиту – PUT, GET, POST, другий – url запиту, третій (необов'язковий) – тип запиту (синхронний або асинхронний), четвертий і п'ятий (також необов'язкові) – для захищених сторінок


send(content)


Надсилає запит серверу


setRequestHeader(header, value)


Встановлює значення певного заголовка. Перед викликом цього методу необхідно викликати метод open


Також XMLHttpRequest містить ряд властивостей, які представлені нижче:

























Властивість



Опис


onreadystatechange


Обробник події, яка виникає при кожній зміні стану запиту


readyState


Стан запиту. Доступні такі значення: 0 – запит неініціалізованих, 1 – завантаження, 2 – завантаження закінчена, 3 – interactive, 4 – complete


responseText


Відповідь сервера у вигляді рядка


responseXML


Відповідь сервера в XML. Цей об'єкт може бути оброблений і перевірений як DOM


status


Код статусу HTML. (Наприклад 200 – OK)


statusText


Назва коду статусу HTML


Побіжно проглянув ці методи, нескладно зрозуміти, які методи досить викликати, щоб за допомогою JavaScript отримати будь-які з сервера.


Перш за все напишемо серверну частину, яка буде повертати просту рядок. Для цього (щоб не було «сторонніх» даних на зразок тегів відкриття закриття html) найбільш раціонально буде створити hanlder. Відкриваємо web-проект в Visual Studio 2005 і створюємо файл типу Handler. Вміст буде приблизно таким:

 <%@ WebHandler Language=”C#” Class=”MyHandler” %>
using System;
using System.Web;
public class MyHandler: IHttpHandler {
    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = “text/plain”;
        context.Response.Write(“Hello World”);
    }
    public bool IsReusable {
        get {
            return false;
        }
    }
}

Тобто при запиті даної сторінки цей hanlder повертає text / plain документ з єдиною строчкою "Hello World". Нас такий handler влаштовує як не можна краще.


Тепер створимо звичайну HTML – сторінку, яка буде і виконувати запит, використовуючи XMLHttpRequest.

 <html xmlns=”http://www.w3.org/1999/xhtml” >
<head>
    <title>Simple XMLHttpRequest page</title>
    <script type=”text/javascript”>
        var xmlHttp;
        function createXMLHttpRequest()
        {
            if (window.ActiveXObject)
            {
xmlHttp = new ActiveXObject ("Microsoft.XMLHTTP");
            }
            else if (window.XMLHttpRequest)
            {
                xmlHttp = new XMLHttpRequest();
            }
        }
        function startRequest()
        {
            createXMLHttpRequest();
            xmlHttp.onreadystatechange = handleStateChange;
            xmlHttp.open(“GET”, “MyHandler.ashx”, true);
            xmlHttp.send(null);
        }
        function handleStateChange()
        {
            if(xmlHttp.readyState == 4)
            {
                if(xmlHttp.status == 200)
                {
alert ("Response:" + xmlHttp.responseText);
                }
            }
        }
    </script>   
</head>
<body>
<Input type = "button" value = "Start Asynchronous Request"
        onclick=”startRequest();”/>
</body>
</html>

Даний код досить простий. При натисканні на кнопку "Start Asynchronous Request" викликається клієнтська функція startRequest, яка в свою чергу спочатку викликає розглянуту нами раніше функцію createXMLHttpRequest для створення об'єкту XMLHttpRequest, після чого чіпляє обробник (клієнтську функцію handleStateChange) на подію ReadyStateChange для цього об'єкта, відкриває і посилає запит. Якщо запитувана сторінка доступна і дані були отримані, status змінює свій стан на 200. Тому у функції handleStateChange ми перевіряємо значення цієї властивості. При потрібному значенні ми за допомогою alert виводимо отримане значення. Пробуємо як це працює:



У даному нескладному коді по суті закладена вся фукциональность AJAX – отримання даних від сервера без перевантаження сторінки. Розуміння цього механізму достатньо, щоб зрозуміти суть AJAX, а також успішно використовувати його у своїх додатках. Далі лише справа техніки і далі ми розглянемо реалізацію всього цього, але з використанням ASP.NET J



Зворотні виклики сторінки.


Зворотні виклики – це спеціальний вид повернення форми, тобто сторінка проходить свій цикл подій, але дані форми повертаються клієнту до початку процесу рендерингу форми, тобто до перемальовування. Як і в будь-якому AJAX виконанні запит починається на клієнтській стороні в результаті виникнення якої-небудь події, при цьому запускається клієнтська вбудована функція під назвою WebForm_DoCallback. Ця функція має наступний прототип:

 WebForm_DoCallback (pageID, argument, returnCallback, context, errorCallback, useAsync);

Де:


pageID – ID сторінки, яка виконує виклик,


argument – рядковий аргумент, який передається серверу,


returnCallback – клієнтська функція або клієнтський скрипт, який повинен виконатися після того, як серверна сторона поверне управління


context – дані, які передаються returnCallback.


errorCallback – клієнтська функція або клієнтський скрипт, що виконується при виникненні помилок


useAsync – встановлює, чи буде запит синхронним або асинхронним.


Наступний етап – серверна сторінка повинна знати, що вона повинна підтримувати зворотні виклики (тобто перш за все повертати дані до початку рендеринга сторінки). Для цього ця сторінка повинна реалізовувати інтерфейс System.Web.UI.IcallbackEventHandler.


Даний інтерфейс містить 2 методи:

 public interface ICallbackEventHandler
{
string GetCallbackResult();
void RaiseCallbackEvent(string eventArgument);
}

Виконання зворотного виклику на серверній стороні складається з 2-х етапів: підготовка і повернення результату. Метод RaiseCallbackEvent викликається першим і призначений для підготовки віддаленого виконання коду. Метод GetCallbackResult виконується пізніше, коли результат уже готовий до відправки. Цей поділ було введено тільки в release версії. NET 2.0, в попередніх версіях ці 2 методи були об'єднані в один (це було зроблено з урахуванням асинхронної роботи). Метод GetCallbackResult повертає string, тому що повертаються дані повинні бути серіалізіровани тим чи іншим методом в рядок, а на клієнті навпаки, десеріалізіровани.


При запиті сторінки з клієнтського скрипта спочатку виконується Init, після чого стандартний цикл подій завантаження сторінки до події Load, в Load властивість IsCallback встановлюється в true, по завершенню Load виконуються методи інтерфейсу ICallbackEventHandler, після чого як вже говорилося вище виконання переривається, не переходячи у стадію рендеринга. Перш за все це говорить про те, що не відбувається стадія збереження ViewState, так що намагатися що-небудь зберегти в ViewState стандартним способом марно (воно і зрозуміло, бо ViewState сторінки не оновлюється). Управляє процесом взаємодії між сторінкою і сервером т.зв. диспетчер зворотних викликів. Диспетчер зворотних викликів має в собі бібліотеку клієнтських сценаріїв. Ці клієнтські сценарії формують і відправляють запит, отримують і розбирають відповідь від сервера і т.д. Подивившись View Source будь-який з сторінок можна побачити рядки на кшталт

 <script src="/WebResource.axd?d=VWLFgbEM584QkLzy5eDwGw2&t=632964616335443742" type="text/javascript"> </ script>

Завантаживши файл, який повертає даний обробник WebResource.axd із зазначеними параметрами, можна заглибитися в вивчення клієнтських скриптів, які відповідають за вказані вище дії J


Метод GetCallbackEventReference


Написання клієнтського методу WebForm_DoCallback не є чим-небудь складним, однак пов'язана з деякими труднощами в разі динамічного генерування або передачею параметрів. Для цього в клас Page.ClientScript (System.Web.UI.ClientScriptManager) введено спеціальний метод – GetCallbackEventReference, який отримує ряд параметрів і, подібно наприклад методом GetPostBackEventReference, генерує відповідний клієнтський код. Я б не сказав, що цей метод дуже витончений, особливо коли необхідно передати параметри в клієнська скрипт (особливо наявність одинарних і подвійних лапок в контатенірующейся рядку псує всю картину), але все зручніше, ніж в лоб писати WebForm_DoCallback.


Даний метод має наступний прототип:

 public string GetCallbackEventReference(
Control target,
string argument,
string clientCallback,
string context,
string clientErrorCallback,
bool useAsync)

де:


target – сторінка або WebControl, який буде обробляти зворотний виклик. Відповідно, ця сторінка або контрол повинні реалізувати інтерфейс ICallbackEventHandler, інакше буде кинуто виняток:

 System.InvalidOperationException: The target "__Page" for the callback could not be found or did not implement ICallbackEventHandler.

Генерят перший параметр функції WebForm_DoCallback


argument – аргумент, який передається клієнтської функції або скрипту. Відповідає другому параметру функції WebForm_DoCallback.


returnCallback – клієнтська функція або клієнтський скрипт, який повинен виконатися після того, як серверна сторона поверне управління (3-й параметр WebForm_DoCallback)


context – дані, які передаються клієнтської returnCallback (4-й параметр WebForm_DoCallback).


errorCallback – клієнтська функція або клієнтський скрипт, що виконується при виникненні помилок (5-й параметр WebForm_DoCallback)


useAsync – встановлює, чи буде запит синхронним або асинхронним (6-й параметр WebForm_DoCallback).


Тепер ми можемо створити нашу першу aspx сторінку з використанням ajax. Припустимо, досить часте завдання – є 2 випадаючих списку – в одному з них дані більш високого рівня, ніж у другому. Тобто при виборі значення в першому списку – другий список перевантажується в залежності від цього значення в першому. Наприклад – перший SELECT містить список виробників машин, другий – моделі машин, які вибраний виробник випускає. Для вирішення цього завдання можна звісно завантажити всі дані в javascript, а потім скриптом перебіндівать другий select. У нашому випадку це в принципі підійшло б, але є кілька мінусів – перший це те, що даних може бути дуже багато (припустимо, 100 виробників і для кожного з них вказані всі моделі, коли або що випускалися, тобто може бути більше 100. Разом вантажити кілька десятків тисяч ітемов в javascript не є кращий варіант). Крім того, доведеться писати не такий вже й простий яваскрипт. Плюс може бути ситуація, коли дані повинні бути інтерактивними.


Спробуємо вирішити це за допомогою AJAX.


Для цього створюємо звичайну ASPX сторінку:

 <form id=”form1″ runat=”server”>
<div>
    <table>
        <tr>
            <td>
                Please, select Manufacturer:
            </td>
            <td>
<asp:DropDownList runat="server" ID="ddlManufacturer"> </ asp: DropDownList>
            </td>
        </tr>
        <tr>
            <td>
                Please, select Model:
            </td>
            <td>
<asp:DropDownList runat="server" ID="ddlModel"> </ asp: DropDownList>
            </td>
        </tr>
    </table>
</div>
</form>

Після чого реалізуємо інтерфейс ICallbackEventHandler для класу сторінки:

 public partial class CarList: System.Web.UI.Page, ICallbackEventHandler
{
    protected string evArg;
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    #region ICallbackEventHandler Members
    public string GetCallbackResult()
    {
throw new Exception ("The method or operation is not implemented.");
    }
    public void RaiseCallbackEvent(string eventArgument)
    {
throw new Exception ("The method or operation is not implemented.");
    }
    #endregion
}

Нам необхідно отримати eventArgument в методі RaiseCallbackEvent, зробити відповідні дії і потім передати його в GetCallbackResult для повернення клієнту. Для цього ми вводимо змінну evArg.


Далі нам необхідно причепити клієнтський обробник для першого SELECT. Тобто при зміні значення повинна викликатися функція WebForm_DoCallback. Так і пишемо J

 protected void Page_Load(object sender, EventArgs e)
{
string argClientFunction = "document.all [" "+ ddlManufacturer.ClientID +" "]. options (document.all [" "+ ddlManufacturer.ClientID +" "]. selectedIndex). value";
string cScript = ClientScript.GetCallbackEventReference (this, argClientFunction, "CallbackFunction", "" CallbackContext "", "null", false);
ddlManufacturer.Attributes.Add ("onchange", cScript + "; return false;");
 }

Тепер напишемо 2 методи, перший з яких потрібен лише один раз – для binding списку виробників, а другий – для списку моделей. Щоб не мучитися з БД зробимо простіше наступним чином:

     void BindManufacturers()
    {
        ddlManufacturers.Items.Add(new ListItem(“Mercedes”));
        ddlManufacturers.Items.Add(new ListItem(“BMW”));
        ddlManufacturers.Items.Add(new ListItem(“Renault”));
        ddlManufacturers.Items.Add(new ListItem(“Toyota”));
        ddlManufacturers.Items.Add(new ListItem(“Daewoo”));
    }
    void BindModels(string manufacturer)
    {
        switch (manufacturer)
        {
            case “Mercedes”:
                ddlModel.Items.Clear();
                ddlModel.Items.Add(new ListItem(“S350”));
                ddlModel.Items.Add(new ListItem(“S500”));
                ddlModel.Items.Add(new ListItem(“S600”));
                ddlModel.Items.Add(new ListItem(“CLK”));
                break;
            case “BMW”:
                ddlModel.Items.Clear();
                ddlModel.Items.Add(new ListItem(“model 3”));
                ddlModel.Items.Add(new ListItem(“model 5”));
                ddlModel.Items.Add(new ListItem(“model 7”));
                ddlModel.Items.Add(new ListItem(“X3”));
                ddlModel.Items.Add(new ListItem(“X5”));
                break;
            case “Renault”:
                ddlModel.Items.Clear();
                ddlModel.Items.Add(new ListItem(“12”));
                ddlModel.Items.Add(new ListItem(“19”));
                ddlModel.Items.Add(new ListItem(“21”));
                break;
            case “Toyota”:
                ddlModel.Items.Clear();
                ddlModel.Items.Add(new ListItem(“Aristo”));
                ddlModel.Items.Add(new ListItem(“Avalon”));
                ddlModel.Items.Add(new ListItem(“Avensis”));
ddlModel.Items.Add (new ListItem ("Bandeirante"));
                break;
            case “Daewoo”:
                ddlModel.Items.Clear();
                ddlModel.Items.Add(new ListItem(“Sens”));
                ddlModel.Items.Add(new ListItem(“Lanos”));
                break;
        }
    }

І отже для того, щоб заповнити список виробників, необхідно додати в Page_Load:

         if (!IsPostBack)
            BindManufacturers();

Тепер залишилося зробити 2 речі – написати клієнтську функцію, яка буде виконуватися після повернення і написати код для функцій RaiseCallbackEvent і GetCallbackResult.


Спочатку напишемо код для цих 2-х функцій:

     public string GetCallbackResult()
    {
        BindModels(evArg);
        evArg = String.Empty;
        for (int i = 0; i < ddlModel.Items.Count; i++)
        {
            evArg += ddlModel.Items[i].Value + “;”;
        }
        return evArg;
    }
    public void RaiseCallbackEvent(string eventArgument)
    {
        evArg = eventArgument;
    }

Значення параметра eventArgument функції RaiseCallbackEvent заносимо у внутрішню змінну evArg (це значення вибраного виробника), а в GetCallbackResult перебіндів список моделей у цю ж змінну заносимо всі значення моделей для даного виробника, розділивши їх наприклад «;» (такий собі спосіб серіалізациі).


Далі напишемо клієнтську функцію CallbackFunction. Ця функція повинна очищати SELECT для моделей і, отримавши строкове значення від GetCallbackResult, десеріалізіровать це значення і заповнити SELECT новими значеннями.

 string scr = “<script language=javascript>”;
scr + = "function CallbackFunction (callbackResult, callbackContext)";
scr += “{“;
scr + = "var ddlModel = document.all [" "+ ddlModel.ClientID + ""];";
scr += ”    var l = ddlModel.options.length;”;
scr += ”    for(var i=0; i<l; i++)”;
scr += ”        ddlModel.options.remove(0);”;
scr += ”    var models = callbackResult.split(“;”);”;
scr += ”    for(var i=0; i<models.length; i++)”;
scr += ”    {“;
scr + = "var oOption = document.createElement (" OPTION ");";
scr += ”        oOption.text = models[i];”;
scr += ”        oOption.value = models[i];”;
scr += ”        ddlModel.options.add(oOption);”;
scr += ”    }”;
scr += ”    return false;”;
scr += “}”;
scr += “</script>”;
RegisterStartupScript(“scr” + this.ClientID, scr);

Ось в принципі і все. Даний приклад звичайно далеко не досконалий (наприклад, не врахована обробка помилок), але цілком працездатний. Ви можете переконатися в цьому, відкривши цю сторінку:




Біблотека ATLAS


Щоб полегшити життя простому програмісту при роботі з AJAX і позбавити його від необхідності вникати у подробиці взаємодії клієнта з сервером – Microsoft розробила бібліотеку, яка містить ряд компонентів, використовують AJAX. Для більшості випадків при використанні цих компонентів навіть немає необхідності знати принципи роботи AJAX. Компоненти ATLAS розміщуються на aspx-сторінці подібно користувальницьким компонентів (По суті ними ж і будучи), так що програмування з їх використанням нічим принципово не відрізняється від програмування з використанням користувальницьких компонентів. Microsoft постійно оновлює цей список, тому я б радив частіше відвідувати web-сайт http://atlas.asp.net для оновлення поточної використовуваної версії на більш нову (крім того, проміжні версії нових ATLAS-контролів або більше ранніх контролів, але з виправленими помилками можна взяти з сайту: … ).


Для того, щоб додати в свій проект ATLAS компоненти потрібно по-перше переконатися, що ATLAS встановлений на вашому комп'ютері, у противному випадку його встановити. Після чого можна або створити проект типу "ATLAS" Web Site, чи додати посилання на бібліотеку. У другому випадку необхідно налаштувати також web.config на використання ATLAS вручну.


На момент написання статті ATLAS включав в себе 21 контрол, деякі з яких використовуються досить часто, інші ж особисто я крім як у тестових додатках ніде не використовував. Контрол CascadingDropDown є ATLAS реалізацією того, що ми написали вище J Найбільш широковживаних і універсальний, на мій погляд, це контрол UpdatePanel – це панель (на клієнті вона перетвориться в div елемент), яку можна перевантажити не перевантажуючи сторінку, причому вона може містити інші контроли. UpdatePanel складається з 2-х частин – ContentTemplate і Triggers. ContentTemplate представляє собою область вмісту ContentTemplate (тобто як я вже говорив, воно може бути з інших ASP.NET контролів, тегів HTML і просто тексту). Triggers містить список тригерів для даної UpdatePanel. Тригер – це як-би обробник події, за яким дана UpdatePanel повинна оновлюватися. Тригери бувають 2-х типів – ControlEventTrigger і ControlValueTrigger. Перший з них реагує на події контрола (наприклад, контроль є Button і перехоплюваним подією подія Click), другий – на зміну властивості (наприклад зміна значення Text для контрола TextBox). Наприклад, наступний код:

 <html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
    <title>Untitled Page</title>
<atlas:ScriptManager EnablePartialRendering="true" ID="scriptManager" runat="server"> </ atlas: ScriptManager>
</head>
<body>
    <form id=”form1″ runat=”server”>
    <div>
<atlas:UpdatePanel runat="server" ID="myUpdatePanel" Mode="Conditional">
            <ContentTemplate>
<asp:Label runat="server" ID="lbl"> </ asp: Label>
            </ContentTemplate>
            <Triggers>
<atlas:ControlEventTrigger ControlID="btn" EventName="Click" />
            </Triggers>
        </atlas:UpdatePanel>
        <br />
<asp:Button runat="server" ID="btn" Text="Click Me" OnClick="btn_Click" />
    </div>
    </form>
</body>
</html>
public partial class test_ajax1 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    protected void btn_Click(object sender, EventArgs e)
    {
        lbl.Text = “Button was clicked”;
    }
}

Буде оновлювати значення Label після натискання кнопки з використанням AJAX. Зверніть увагу, що даний код практично нічим не відрізняється від «класичного» ASP.NET коду. Перемістивши Label з UpdatePanel – Ми отримаємо «класичний» варіант: була натиснута кнопка – зроблений запит до сервера – сторінка пройшла повний цикл завантаження сторінки – оновлено значення елемента Label – сторінка повернута клієнтові. Це дозволяє легко адаптувати під використання ATLAS і навпаки. Однак є ще один рядок в коді, на яку ви напевно не звернули увагу – це ScriptManager в заголовку сторінки. Цей елемент додає в повертається клієнтові сторінку всі необхідні для ATLAS клієнтські скрипти і цей елемент є обов'язковим (і в єдиному екземплярі на сторінці) у разі використання ATLAS. Також хочу попередити, що у разі використання ControlValueTrigger необхідно на перевіряється контрол AutoPostBack = "true", інакше він просто не буде спрацьовувати. Для того, щоб зміцнити свої знання і спробувати використання ATLAS на практиці-створимо найпростіший чат. Але в нашому чаті буде одна особливість – він буде використовувати AJAX технологію і завдяки цьому він буде інтерактивним. У чатах колишніх часів доводилося або час від часу (наприклад, кожні 20 сек) перевантажувати всю сторінку – при цьому відразу спливало кілька великих недоліків:



  1. <! [Endif]> (і найбільший) якщо користувач набирав текст і в цей момент підходив час перевантаження – користувач втрачав фокус введення і відповідно ту частину повідомлення, яку він вже набрав
  2. <! [Endif]> перевантаження змушувала користувача чекати, поки сторінка буде завантажена і відповідно йому доводилося споглядати на білу сторінку з індикатором завантаження внизу
  3. <! [Endif]> перевантаження не можна було зробити дуже частого, тому що крім самого тексту доводилося завантажувати також всі атрибути сторінки – картинки, логотипи, банери, розмітку HTML

Для боротьби з цим явищем стали використовувати фрейми, що дозволяло перевантажувати тільки один кадр, при цьому користувач не втрачав фокус і не доводилося завантажувати частину сторінки, що знаходиться поза даним фрейму. Проте недоліки як перевантажуються фрейм з білим тлом і резметка HTML все одно залишилися, плюс до них додалися недоліки використання самих фреймів. Використання AJAX дозволяє повністю позбавитися від всіх цих недоліків – дані передаються тільки ті, які потрібно, а саме тільки текст (без розмітки HTML – розмітка встановлюється javascript "ом) і в оптимальному варіанті тільки НОВІ повідомлення (при цьому старі у міру потреби видаляються також javascript "ом). Таким чином зниження трафіку в сотні, а то й тисячі, раз дозволяє зменшити час між запитами аж до декількох секунд. При цьому користувач не бачить процесу завантаження – йому здається, що все відбувається на його машині.


Створення такого чату з урахуванням всіх можливостей AJAX я надам читачеві, а от з використанням компонента ATLAS – UpdatePanel – ми створимо зараз.

 <html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
    <title>Untitled Page</title>
<atlas:ScriptManager EnablePartialRendering="true" ID="scriptManager" runat="server" />
</head>
<body>
    <form id=”form1″ runat=”server”>
    <div>
<atlas:UpdatePanel runat="server" ID="up" Mode="Conditional">
            <ContentTemplate>
<asp:Literal runat="server" ID="lc"> </ asp: Literal>
            </ContentTemplate>
            <Triggers>
<atlas:ControlEventTrigger ControlID="btn" EventName="Click" />
            </Triggers>
        </atlas:UpdatePanel>
        <br />
        <table>
            <tr>
                <td>Your name:</td>
                <td>
<asp:TextBox runat="server" ID="txtName"> </ asp: TextBox>
                </td>
            </tr>
            <tr>
                <td>Your Message:</td>
                <td>
<asp:TextBox runat="server" ID="txtMessage" TextMode="MultiLine"> </ asp: TextBox>
                </td>
            </tr>
            <tr>
                <td colspan=”2″>
<asp:Button runat="server" ID="btn" Text="Add message" OnClick="btn_Click" />
                </td>
            </tr>
        </table>
    </div>
    </form>
</body>
</html>
public partial class chat : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }
    protected void btn_Click(object sender, EventArgs e)
    {
string mes = txtName.Text + "says>" + txtMessage.Text + "<BR>";
/ / Використовуємо саме доступне сховище для повідомлень – Application.
        if (Application[“messages”]==null)
        {
            Application[“messages”] = mes;
        }
        else
        {
Application ["messages"] = ((string) Application ["messages"]) + mes;
        }
        lc.Text = Application[“messages”].ToString();
    }
}

У даному прикладі тригер для UpdatePanel висить на кнопку btn, тобто UpdatePanel буде оновлюватися тільки в разі натискання на цю кнопку. Нам же необхідно щоб UpdatePanel оновлювався також через певні проміжки часу. Немає стандартних способів змусити оновлюватися UpdatePanel за допомогою javascript. Я роблю це таким чином:


1. На форму додаю ще одну кнопку і роблю її невидимою.

 <asp:Button runat="server" ID="btnUpdate" Visible="false" />

2. Створюю наступний javascript:

 string scr = "<script language=javascript>";
        scr += “function UpdatingPanel()”;
        scr += “{“;
scr + = "" + Page.ClientScript.GetPostBackEventReference (btnUpdate, "") + ";";
        scr += “}”;
        scr += “</script>”;
        RegisterStartupScript(“scr” + this.ClientID, scr);

3. У UpdatePanel додаю тригер для цієї кнопки:

 <atlas:ControlEventTrigger ControlID="btnUpdate" EventName="Click" />

Також потрібно прописати в <% @ Page%> – EnableEventValidation = "false"


4. А також в тег body: onload = "setInterval (" UpdatingPanel () ", 3000);"


Як це працює – клієнтська функція UpdatingPanel грубо кажучи імітує натискання на кнопку btnUpdate. Оскільки в UpdatePanel є тригер для цієї кнопки – то виклик цієї клієнська функції викличе оновлення UpdatePanel. Нам залишається тільки викликати цю клієнтську функцію через певні проміжки часу, що ми і робимо в body.


У результаті у нас вийшов наступний код:

 <% @ Page Language = "C #" AutoEventWireup = "true" CodeFile = "chat.aspx.cs" Inherits = "test_chat" EnableEventValidation = "false"%>
<% @ Register Assembly = "AtlasControlToolkit" Namespace = "AtlasControlToolkit" TagPrefix = "atlasToolkit"%>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
    <title>Untitled Page</title>
<atlas:ScriptManager EnablePartialRendering="true" ID="scriptManager" runat="server" />
</head>
<body onload=”setInterval(“UpdatingPanel()”, 3000);”>
    <form id=”form1″ runat=”server”>
    <div>
<asp:Button runat="server" ID="btnUpdate" Visible="false" />
<atlas:UpdatePanel runat="server" ID="up" Mode="Conditional">
            <ContentTemplate>
<asp:Literal runat="server" ID="lc"> </ asp: Literal>
            </ContentTemplate>
            <Triggers>
<atlas:ControlEventTrigger ControlID="btn" EventName="Click" />
<atlas:ControlEventTrigger ControlID="btnUpdate" EventName="Click" />
            </Triggers>
        </atlas:UpdatePanel>
        <br />
        <table>
            <tr>
                <td>Your name:</td>
                <td>
<asp:TextBox runat="server" ID="txtName"> </ asp: TextBox>
                </td>
            </tr>
            <tr>
                <td>Your Message:</td>
                <td>
<asp:TextBox runat="server" ID="txtMessage" TextMode="MultiLine"> </ asp: TextBox>
                </td>
            </tr>
            <tr>
                <td colspan=”2″>
<asp:Button runat="server" ID="btn" Text="Add message" OnClick="btn_Click" />
                </td>
            </tr>
        </table>
    </div>
    </form>
</body>
</html>
public partial class chat : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string scr = “<script language=javascript>”;
        scr += “function UpdatingPanel()”;
        scr += “{“;
scr + = "" + Page.ClientScript.GetPostBackEventReference (btnUpdate, "") + ";";
        scr += “}”;
        scr += “</script>”;
        RegisterStartupScript(“scr” + this.ClientID, scr);
        InitMessage();
    }
    void InitMessage()
    {
        if (Application[“messages”] != null)
            lc.Text = Application[“messages”].ToString();
    }
    protected void btn_Click(object sender, EventArgs e)
    {
string mes = txtName.Text + "says>" + txtMessage.Text + "<BR>";
        if (Application[“messages”]==null)
            Application[“messages”] = mes;
        else
Application ["messages"] = ((string) Application ["messages"]) + mes;
        lc.Text = Application[“messages”].ToString();
    }
}

Для того, щоб спробувати цей найпростіший варіант чату з використанням ATLAS на практиці – відкрийте кілька броузерів з даною сторінкою і в кожному з них напишіть за повідомленням. При цьому можете бачити, що після написання у другому броузері повідомлення в першому воно з'явиться через 3 секунди.



У даній статті я описав основи роботи з AJAX в ASP.NET і сподіваюся, що вона допоможе програмістам почати використання цієї технології у своїх ASP.NET додатках.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*