То, о чём писал в твиттере, но не мог написать в блоге раньше. 

Была небольшая и, на первый взгляд, достаточно простая задача - показать на странице таблицу, с возможностью сортировки и автообновления. Ну ещё и поиск по ней. После некоторого времени, потраченного на поиск и попытки исправления существующих решений стало понятно, что написать с нуля будет быстрее и дешевле (тут имеется в виду также дальнейшая поддержка всего этого). Готовые реализации javasctipt-библиотек и плагинов к jQuery были или слишком уж навороченный для данной задачи или, мягко говоря, очень плохо справлялись с обновлением таблицы и последующей сортировкой. Результатом этого всего стало написание плагина для jQuery c нуля.

Коротко о плагине:

 

  • позволяет автоматически обновлять и сортировать таблицы;
  • построен на базе jQuery Template (в будущем планируется версия без этого);
  • сортировка работает исходя из данных что пришли от сервера в JSON, и не зависит от html-разметки;
  • маленький размер и минимум функциональности.

Более подробно с примерами и какой-то документацией о плагине можно почитать на http://ajaxtable.e0ne.info/. Также страница в официальном репозитории пакетов http://plugins.jquery.com/project/jQueryAjaxTable и исходники на GitHub: https://github.com/e0ne/jQuery-AjaxTable.

Комментарии, пожелания и замечания очень приветствуются.

 


Рано или поздно при написании JavaScript’а возникает необходимость в том, чтобы он был автоматически запущен при загрузке страницы. Нужно это, как правило, для следующих действий: инициализация интерфейса (UI) и отложенная загрузка данных (lazy load).
Как часто бывает, для такой простой на первый взгляд задачи, есть несколько способов решения.

Задача. После загрузки страницы, нам нужно каким-то образом проинициализировать меню функцией initiPageMenu(), которыя находится в файле menu.js.

Способы решения:

1. Самый простой способ: в конце js-файла делаем вызов нужной функции.

menu.js:
// some javascript code
initiPageMenu();
// end of file

Самый простой способ имеет множество недостатков:

  • если скрипт подключается в теге <head>, у него нет доступа к DOM-модели;
  • вызов необходимой функции блокирует загрузку других скриптов;
  • необходимо учитывать, что к моменту загрузки скрипта, DOM-модель существует и все необходимые зависимости учтены (например, загружен другой скриат).
  • при просмотре файла menu.js не всегда очевидно, что будет выполнена функция initiPageMenu();
  • данный способ ничего не знает о UpdatePanel.

2. На серверной стороне в событии OnLoad или OnPreInit добавить следующий код:

ScriptManager.RegisterStartupScript(this,  this.GetType(), "initiPageMenu", “initiPageMenu();”, true);

Этот способ значительно лучше. Вызов функции initiPageMenu() будет помещен в конец тега <body>. Из недостатков отмечу следующее:

  • при изменении имени функции необходимо перекомпилировать серверный код со всеми вытекающими отсюда последствиями;
  • вызов клиентской (javascript) функции находится в серверном коде - ничего плохого в этом нет, но, imho, теряется красота кода на стороне сервере; хочу отметить, что во многих случаях этот вариант остаются единственным возможным (когда необходимо передать в клиентский код значение серверной переменной).

3. В файле menu.js добавить функцию page_load():

function page_load() {
    initiPageMenu();
}

После загрузки страницы, ScriptManager ищет все обработчики page_load() и выполняет их в порядке загрузки. К моменту начала выполнения этой функции страница уже полностью загруженна браузером и есть доступ к DOM-модели.

Недостатки:

  • неширокая распространённость данного подхода (а недостаток ли это?);
  • не работает без использования на странице ScriptManager (а такие страницы ещё остались!).

4. Последний способ, о котором я хочу рассказать - событие document.ready() при использовании jQuery:

$(document).ready(initiPageMenu());

Недостаки тут тоже есть (куда же без них?)

  • необходимо использовать библиотеку jQuery;
  • как и первый, данный способ также ничего не знает о UpdatePanel.


Какой способ использовать - каждый должен выбрать сам. Единственное, на что необходимо обратить внимание - использование нескольких способов одновременно сильно усложняет понимание и сопровождение кода. Исключением из этого правила является пункт 2, но и его можно обойти при использовании IScriptControl и клиентских событий AjaxScriptManager.


1. Введение
2. Обзор framework'а
3. Жизненный цикл страницы
4. Полезные объекты и функции

1. Введение

В предыдущем посте из этой серии (ASP.NET Ajax. Часть 1: что внутри?) я рассказал что такое AJAX и как Microsoft помогает нам его использовать. Сегодня я более подробно расскажу о его клиентской части. Частично из-за того, что эту информацию не так просто найти в MSDN, как хотелось бы, частично  из-за того, что в последнее время Microsoft уделяет этой части всё меньше внимания, агитируя использовать jQuery, многие разработчики даже на догадываются какой мощных инструмент находится у них в руках.

2. Обзор framework'а

По умолчанию, эти скрипты грузятся на страницу, на которой есть ScriptManager по ссылке вида ScriptResource.axd?d=scriptIdentificator. Сами же скрипты находятся в ресурсах сборки System.Web.Extensions (если у кого-то всё-ещё установлена VS2005, то эти скрипты можно найти в папке c:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\v1.0.61025\MicrosoftAjaxLibrary\System.Web.Extensions\). Также можно загружать эти скрипты с помощью CDN. Подробнее об этом способе можно почитать тут.
Сам скирт немного отличается для WebForms и ASP.NET MVC, но ядро у них общее.
Все функции/объекты разделены на пространства имён (namespaces) по аналогии с серверной частью. Перечислять я их не буду, так как на MSDN (http://msdn.microsoft.com/en-us/library/bb397536.aspx, http://msdn.microsoft.com/en-us/library/dd410060.aspx) всё хорошо описано.

3. Жизненный цикл страницы

Кроме стандартных для DOM модели событий, ASP.NET Ajax предоставляет нам  доступ как к событиям всего приложения (init, load, unload и др.), так и события, связанные с запросами на сервер (beginRequest, endRequest и др.). Как всегда, за полной информацией лучше обратиться в первоисточник, а именно - http://msdn.microsoft.com/en-us/library/bb386417.aspx.

4.Полезные объекты и функции

MS Ajax Library предоставляет нам как новые типы/функции, так и расширения для стандартных - Array, Number, Date, String и др., о которых можно почитать в MSDN Magazine (http://msdn.microsoft.com/en-us/magazine/cc163300.aspx).
Одними из наиболее частоиспользуемых являются функции $get() и $find():
- $get()  - оптимизированный по производительности аналог document.getElementById, который ищет элемент по его ID и в качестве второго параметра может принимать parent-элемент, в котором нам необходимо найти нужный элемент DOM-модели.
- $find() - функция, которая очень похожа на $get(), но возвращает не DOM-элемент, а экзепмляр Ajax Client Control.
Более детальное описания использования этих функций: http://mattberseth.com/blog/2007/08/the_everuseful_get_and_find_as.html


На днях столкнулся такой ситуацией, что многие некоторые разработчики при упоминании Ajax имеют в виду компонент UpdatePanel и не понимают как она работает. Сегодня я решил попытаться исправить эту ситуацию и рассказать что такое и как устроен ASP.NET Ajax.

 Для начала обратимся Википедии и посмотрим, что такое Ajax:

AJAX (Asynchronous Javascript and XML — «асинхронный JavaScript и XML») — это подход к построению интерактивных пользовательских интерфейсов веб-приложений, заключающийся в «фоновом» обмене данными браузера с веб-сервером. В результате при обновлении данных веб-страница не перезагружается полностью, и веб-приложения становятся более быстрыми и удобными.

Для выполнения асинхронных запросов, на JavaSctipt необходимо создать объект XMLHttpRequest, который и будет взаимодействовать с сервером. В зависимости от браузера, объект создаётся разными способами, но можно написать универсальный метод для его создания:

    function createRequestObject()
    {
    if (window.XMLHttpRequest) {
    try {
    return new XMLHttpRequest();
    } catch (e){}
    } else if (window.ActiveXObject) {
    try {
    return new ActiveXObject('Msxml2.XMLHTTP');
    } catch (e){
    try {
    return new ActiveXObject('Microsoft.XMLHTTP');
    } catch (e){}
    }
    }
    return null;
    }
 

 

Теперь вернёмся в ASP.NET. Как несложно догадаться, Microsoft ASP.NET Ajax имееит клиент-серверную архитектуру:

Серверная часть Microsoft ASP.NET Ajax отвечает за авторизацию и аутентификацию пользователей, генерацию и регистрацию на странице необходимых скриптов, имеет всё необходимое для работы с веб-службами, включая генерацию proxy-классов, xml и JavaScript сериализацию. Также доступно несколько компонентов (ScriptManager, UpdatePanel, UpdateProgress и Timer), которых вполне достаточно для реализации базовых функций.

Клиентская часть имеет название Microsoft AJAX Library и состоит из нескольких JavaScript файлов, с помощью каких взаимодействие с сервером становится проще. В этой библиотеке доступно множество классов, для взаимодействия с веб-службами, работы с DOM-моделью браузера, имебтся базовые классы для создания собственных контролов.

В следующих постах я расскажу подробнее о том, как работает серверная часть и загляну внутрь Microsoft AJAX Library.

Ссылки, где можно почитать подробнее об ASP.NET AJAX:


Время от времени приходится организовывать возможность загрузки пользователями файлов на сервер: загрузка аватарок, файлов для галереи и т.д.  

Для решения этой задачи существует стандартный ASP.NET компонент FileUpload, который, в свою очередь, педставляет html-тэг <input type="file" />. В простнйшем случае код для загрузки файлов будет выглядеть так:

  •  Default.aspx:
    1. <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
    2.  
    3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    4.  
    5. <html xmlns="http://www.w3.org/1999/xhtml">
    6. <head runat="server">
    7.     <title></title>
    8. </head>
    9. <body>
    10.     <form id="form1" runat="server">
    11.     <div>
    12.         <asp:FileUpload ID="fu" runat="server" />
    13.        
    14.         <input type="submit" value="Upload" />
    15.     </div>
    16.     </form>
    17. </body>
    18. </html>
    19.  
    20.  

  • Default.aspx.cs
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Web;
    5. using System.Web.UI;
    6. using System.Web.UI.WebControls;
    7. using System.IO;
    8.  
    9. namespace WebApplication1
    10. {
    11.     public partial class _Default : System.Web.UI.Page
    12.     {
    13.         protected void Page_Load(object sender, EventArgs e)
    14.         {
    15.             if (IsPostBack && fu.FileContent != null)
    16.             {
    17.                 fu.PostedFile.SaveAs(path);
    18.             }
    19.         }
    20.     }
    21. }
    22.  
    23.  
Этот способ имеет несколько недостатков, один из которых - необходимость делать полный postback. Поэтому возникает желание сделать это с промощью AJAX. Т.к. использование AJAX подразумевает собой применение объекта XMLHttpRequest, который из-за соображений безопастногсти запрещает передавать на сервер файлы, то решать данную задачу приходится другим способом. А именно с использованием iframe.
Переделаем предыдущий варивант и с приминением ifame:
  • Default.aspx: 
    1. <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
    2.  
    3. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    4.  
    5. <html xmlns="http://www.w3.org/1999/xhtml">
    6. <head runat="server">
    7.     <title></title>
    8. </head>
    9. <body>
    10.     <script type="text/javascript">
    11.         function onFormSubmit() {
    12.             var formUpload = document.getElementById('form1');
    13.             formUpload.target = 'upload_target';
    14.             formUpload.action = 'default.aspx';

    15.         }
    16.     </script>
    17.     <form id="form1" onsubmit="onFormSubmit();">
    18.     <div>
    19.         <input id="file1" type="file" name="file1" /> <br />
    20.         <input id="file2" type="file" name="file2" />
    21.        
    22.         <input type="submit" value="Upload" />
    23.        
    24.         <iframe id="upload_target1" name="upload_target" src="" style="width:0;height:0;border:0px solid #fff;"></iframe>
    25.     </div>
    26.     </form>
    27. </body>
    28. </html>
    29.  

  • Default.aspx.cs:
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Web;
    5. using System.Web.UI;
    6. using System.Web.UI.WebControls;
    7. using System.IO;
    8.  
    9. namespace WebApplication1
    10. {
    11.     public partial class _Default : System.Web.UI.Page
    12.     {
    13.         protected void Page_Load(object sender, EventArgs e)
    14.         {
    15.             if (IsPostBack)
    16.             {
    17.                 HttpFileCollection uploads = HttpContext.Current.Request.Files;
    18.                 for (int i = 0; i < uploads.Count; i++)
    19.                 {
    20.                     HttpPostedFile upload = uploads[i];
    21.  
    22.                     if (upload.ContentLength == 0)
    23.                         continue;
    24.  
    25.                     upload.SaveAs(path);
    26.                 }
    27.  
    28.             }
    29.         }
    30.     }
    31. }
    32.  
    33.  
Таким образом мы получаем ajax-эффект закгрузки файлов на сервер. Ещё одним интересным способом загрузки файлов является использование flash-компонентов (http://www.swfupload.org/). Готовый к приминению ajax-компонент можно скачать здесь: http://ajaxuploader.com/. Посмотреть how-to видео можно на сайте ASP.NET (http://www.asp.net/learn/videos/)

Свершилось! Несколько дней назад вышел 8319-81da479ab0d7&displaylang=en" target="_blank">.net 3.5 service pack 1. В месте с ним мы получили ASP.NET Dynamic Data, Entity Framework,  ADO.NET Data Services и много чего другого. Подообнее можно почитать тут.

Но, разумеется, в каждой бочке мёда найдётся своя ложка дёгтя. Ей стал Ajax Control Toolkit, а именно одни из его базовых компонентов - ToolkitScriptManager. После установки .net 3.5 sp1 ToolkitScriptManager, входящий в состав Microsoft Ajax Control toolkit, перестал правильно функционировать. Разработчики компонентов достаточно быстро отреагировали  и выпустили новый релиз, который имеет совместимость с носледней версией .net framework. Так что ставим новую версию, и продолжаем использовать пусть и не лучшую, но уже ставшую достаточно популярной связку MS Ajax и Ajax Control Toolkit. Новую версию тулкита качает здесь.


Интеграция различных скриптов на страницу, где используется MS Ajax - задача нередкая, но единого решения для неё не существует. Я поделюсь с вами некоторыми методами, которые помогут интегрировать срипт в вашу страницу.

  • Никогда не подключайте скрипты с помощью тега <script src="..."></script>. Вместо этого следует использовать копмонени ScriptManager либо ScriptManagerProxy.
  • Что бы не говорили разработчики MS Ajax и AjaxControlToolkit, в конец каждого файла со скриптом следует добавить такой код:
    if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
    Данный код указывает на то, что скрипт полностью загрущился и можно его выполнять.
  • Если скрипт необходимо подгружать только в определённых ситуациях (например, добавление нового компонента на форму), то его следует регистрировать с помощью статических методов класса ScriptManager вида RegisterClientScriptXXX().
  • Для выполнения скрипта после загрузки на страницу есть несколько методов:
    1) использовать клиентское событие EndRequest;
    2) создать функцию с именем pageLoad() - метод аналогичен первому;
    3) если скрипт необходимо зарегистрировать с помощью серверного кода, то используйте метод ScriptManager.RegisterStartupScript().

Эти методы не являются панацеей от всех бед, но помогают экономить часть времени, необходимого на интеграцию скриптов. Иногда хватает только этого, иногда приходится часами отлаживать чужой javascript, но знать о них, как я думаю, должен каждый разработчик, использующий MS Ajax.