"ASP.NET Atlas" – AJAX в исполнении Microsoft
Игорь Тамащук
Введение
Словосочетание "Web 2.0" знакомо сейчас, пожалуй, всем, кто более или менее внимательно следит за развитием Internet-а. И всем, наверное, знаком термин AJAX, который используется в этой концепции. В своей статье я расскажу о проекте Atlas – фреймворке для разработки AJAX web-приложений, который предлагает компания Microsoft разработчикам на ASP.NET.
С чего начать?
Конечно, скачать и установить. Последнюю версию Atlas можно скачать с сайта http://atlas.asp.net/. Выполнив установку пакета VSI, в Visual Studio 2005 вам будет доступен новый тип проектов – ASP.NET "Atlas" Web Site.
Кроме того, на сайте проекта вы можете скачать набор лабораторных работ и хороший пример приложения – “Atlas Wiki”. С их помощью вы сможете шаг за шагом изучить все основные возможности этой библиотеки.
Пример: автозаполнение и частичный рендеринг формы
Можно много писать о том, что же такое AJAX, концептуальной составляющей Atlas, заглядывать в Road Map, сравнивать с альтернативными продуктами. Но, конечно же, ничего лучше не расскажет о библиотеке, чем показательный пример.
Все наверняка видели, как работает web-интерфейс почтовой система GMail. И все помнят, одну из приятных возможностей, доступных пользователю – автозаполнение поля адреса получателя. В нашей статье мы попробуем повторить подвиг разработчиков из команды GMail, разработав небольшую поисковую систему, с использованием Atlas.
Создание проекта
Итак, Atlas установлен. Открываем Visual Studio 2005, создаем новый сайт, в качестве типа сайта выбираем "ASP.NET 'Atlas' Web Site", выбираем место размещения сайта и нажимаем "ОК". У вас должна получиться следующая структура проекта:
Сайт Atlas на самом деле не представляет из себя ничего сложного. Для того чтобы подключить Atlas к любому сайту, нужно выполнить несколько шагов:
Добавить ссылки на сборку Microsoft.Web.Atlas.dll;
Добавить в проект папки со скриптами Atlas;
Сконфигурировать сайт должным образом.
Третий шаг – самый "емкий" из всех. Поэтому распишем его подробнее.
Для начала необходимо зарегистрировать конфигурационную секцию для Atlas:
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<configSections>
<sectionGroup name="microsoft.web" type="Microsoft.Web.Configuration.MicrosoftWebSectionGroup">
<section name="converters" type="Microsoft.Web.Configuration.ConvertersSection"/>
</sectionGroup>
</configSections>
…..
И добавить саму секцию, сразу после ее описания:
<microsoft.web>
<converters>
<add type="Microsoft.Web.Script.Serialization.Converters.DataSetConverter"/>
<add type="Microsoft.Web.Script.Serialization.Converters.DataRowConverter"/>
<add type="Microsoft.Web.Script.Serialization.Converters.DataTableConverter"/>
</converters>
</microsoft.web>
Вкратце, чтотакоеконвертеры. Забегая вперед, скажу, что Atlas-сайт может взаимодействовать с серверной логикой посредством web-сервисов. Методы сервисов могут возвращать клиенту данные произвольных типов: DataSet, string[], DataTable и т.д. Но в этом месте мы получаем так называемый "архитектурный разрыв". Если в качестве клиента выступает любое другое .NET приложение, то в большинстве случаев типы, используемые в декларации сервисов, находят свои отражения и на клиентской стороне. DataSet это DataSet, массив строк – это массив строк. В случае же, когда мы имеем дело с гетерогенными системами, общающимися через web-сервисы, встает проблема узнавания и преобразования типов. То есть мы в нашем случае должны ответить на вопрос, как наш javascript-клиент будет взаимодействовать с web-сервисом, который возвращает выборку данных в виде DataSet? Что такое DataSet для клиента?
Так вот, в нашей конфигурации мы и указали, как Atlas будет обеспечивать "узнаваемость" таких возвращаемых типов, как DataSet, DataTable и DataRow, преобразовывая их в известные и понятные для клиентского кода структуры.
После настройки конвертеров, добавим в файл web.config следующую секцию:
<system.web>
<pages>
<controls>
<add namespace="Microsoft.Web.UI" assembly="Microsoft.Web.Atlas" tagPrefix="atlas"/>
<add namespace="Microsoft.Web.UI.Controls" assembly="Microsoft.Web.Atlas" tagPrefix="atlas"/>
</controls>
</pages>
Здесь мы просто-напросто регистрируем глобально контролы Atlas для использования.
Следующая секция играет более важную, если не самую важную роль во всей конфигурации Atlas:
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="*.asmx" type="Microsoft.Web.Services.ScriptHandlerFactory" validate="false"/>
</httpHandlers>
Здесь мы подменяем стандартный HttpHandler для web-сервисов, на HttpHandler, который поставляется с Atlas. Таким образом, мы делаем вывод, что использование сторонних web-сервисов, не приспособленных для работы с Atlas-клиентами – невозможно в принципе. Все дело в маленькой уловке: клиентская инфраструктура Atlas общается с web-сервисами не посредством стандартного SOAP, а с помощью некого расширенного интерфейса и не обязательно SOAP.
Следующая и последняя конфигурационная секция добавляет для внутренних нужд серверной части Atlas специальный HttpModule.
<httpModules>
<add name="ScriptModule" type="Microsoft.Web.Services.ScriptModule"/>
</httpModules>
Итак, первый шаг завершен, и мы можем приступить к разработке.
Добавление web-сервиса.
Разработка web-сервисов для atlas-сайта в общем случае не требует от разработчика никаких дополнительных действий. Поэтому просто добавим web-сервис SearchService.asmx со следующим интерфейсом:
public class SearchService : System.Web.Services.WebService
{
/// <summary>
/// Метод, который будет возвращать список слов для автозаполнения
/// </summary>
[WebMethod]
public string[] GetAutoCompleteList(string PrefixText, int count)
{
…
}
}
Этот метод будет возвращать список слов для автозаполнения. Важно отметить некоторую особенность этого метода, которая, может быть, связана только с тем, что Atlas сейчас все еще находится в стадии разработки. Дело в том, что для нормальной работы механизма автозаполнения сигнатура этого метода должна совпадать не только по количеству, типам и очередности параметров, но и по именам этих параметров. В противном случае метод будет получать null и 0 соответственно в качестве значений при вызове.
Реализация формы: ввод строки для поиска
Теперь переходим к самой интересной части – созданию работающей формы. В нашем вновь созданном проекте уже есть форма – откроем ее, и изучим структуру.
Первое, что мы видим, это следующий контрол:
<atlas:ScriptManager ID="ScriptManager1" runat="server" />
Для того чтобы понять, для чего он нужен, просто посмотрим на HTML формы, которую получит Internet Explorer. Таммынайдемследующуюстроку:
<script src="ScriptLibrary/Atlas/Debug/Atlas.js" type="text/javascript"></script>
А если мы посмотрим, что получить, например Mozila Firefox, то увидим что ScriptManager отрендерился две строки:
<script src="ScriptLibrary/Atlas/Debug/AtlasCompat.js" type="text/javascript"></script>
<script src="ScriptLibrary/Atlas/Debug/Atlas.js" type="text/javascript"></script>
То есть, этот контрол просто распознает тип браузера клиента и рендерится в строки подключения необходимых и совместимых скриптов, для работы Atlas.
Дадим этому контролу осмысленное название и перенесем его внутрь тэга <head>, чтобы он не путался под ногами в режиме дизайна формы:
<head runat="server">
<title>Untitled Page</title>
<atlas:ScriptManager ID="scriptManager" runat="server">
</atlas:ScriptManager>
</head>
Следующее, что мы видим в исходном тексте формы, это следующую конструкцию:
<script type="text/xml-script">
<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<references>
</references>
<components>
</components>
</page>
</script>
Это одна из "изюминок", которые Atlas предоставляет разработчикам. А именно – механизм для декларативной разработки функциональности форм. Вкратце, это способ разработки, когда вы не описываете последовательность действий, приводящих к тому или иному результату (императивно), а описываете (декларируете) правила взаимодействия компонентов, составляющих форму. Таким образом, форма будет представлять собой что-то вроде часов
Тема декларативного программирования сейчас очень активно разрабатывается. И, стоит заметить, что декларативный стиль разработки Atlas является неким следованием генеральной линии Microsoft в области программирования пользовательского интерфейса: декларативные принципы программирования используются для графической подсистемы Avalon в новейшей операционной системе Microsoft Vista.
Итак, из чего состоит типичный блок atlas-скрипта? Первая секция, которую мы видим в корневом тэге <page> это <references>. Внутри этого тэга описываются все подключения пользовательских файлов скриптов. Вторая секция – это <components>. В этой секции непосредственно и описываются компоненты и их взаимодействие.
В нашем примере мы не будем писать свои atlas-скрипты, поэтому смело удалим этот блок.
Если мы сейчас запустим наше приложение и посмотрим результирующий html, то мы найдем там такой же блок, как мы удалили. Это результат работы контрола ScriptManager. Т.е. кроме подключения скриптов этот контрол еще и генерирует тело atlas-скрипта. А что же нужно делать для того, чтобы эту заглушку наполнить смыслом? А это мы увидим ниже.
Теперь добавим на форму поле для ввода строки поиска, которое и будет "автозаполняться" с помощью Atlas и кнопку, которая будет активизировать поиск.
<asp:TextBox ID="tbSearch" runat="server"
Width="300px"></asp:TextBox>
<asp:Button ID="btnSearch" runat="server" Text="НАЙТИ" />
Ну и, наконец, первый Atlas-контрол – AutoCompleteExtender. Как вы догадались по названию, этот контрол и реализует всю логику по автозаполнению.
Контролы-"расширители" являются одной из основных концепций Atlas. Суть этой концепции в том, что AJAX-функциональность как бы приаттачивается к вполне обычным контролам и не требует от разработчика использования каких-то особых контролов, особых методов. Интересно было наблюдать за эволюцией мысли в команде Atlas – ранние версии библиотеки поставляли целый букет специальных Atlas-контролов, таких как AtlasTextBox, AtlasButton и т.д. А в декабрьском релизе разработчиков ждал сюрприз – все эти контролы просто исчезли, зато появились Extenders.
Итак, добавим на форму экземпляр AutoCompleteExtender.
<atlas:AutoCompleteExtender
ID="extSearchAutoCompleteExtender" runat="server">
<atlas:AutoCompleteProperties Enabled="true"
ServicePath="SearchService.asmx"
ServiceMethod="GetAutoCompleteList"
TargetControlID="tbSearch" />
</atlas:AutoCompleteExtender>
Как видите, все достаточно просто. Мы просто указали контролу путь к web-сервису, название метода и контрол, который будет расширен логикой автозаполнения.
Теперь мы можем посмотреть, что у нас получилось:
Глянем, как же выглядит результирующий html. Интересным для нас будет следующий код:
<script type="text/xml-script">
<page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
<components>
<control id="tbSearch">
<behaviors>
<autoComplete serviceURL="SearchService.asmx" serviceMethod="GetAutoCompleteList" />
</behaviors>
</control>
</components>
</page></script>
Мы видим, что это тот же самый блок, сгенерированный ScriptManager-ом, но с заполненным тэгом <controls>. Таким образом, мы отметим еще одну важную архитектурную особенность Atlas: все Atlas контролы рендерятся в некий xml, за размещение которого отвечает ScriptManager.
Реализация формы: вывод результатов запроса.
Для вывода результатов запроса мы воспользуемся контролом, играющим важную роль в концепции Atlas. Речь идет об UpdatePanel. Этот контрол реализует функциональность по частичному рендерингу и постбэку формы. Используя его вы можете "перерисовывать" только часть формы, экономя на трафике и, что самое важное, сохраняя состояние контролов формы и значения javascript-переменных.
В нашем случае мы будем выводить результаты поиска, не перегружая всю форму целиком, а только ту ее часть, которая будет отображать выборку.
Для того, чтобы продемонстрировать, насколько это просто делается, сначала реализуем логику обработки поискового запроса в классическом postback-стиле, а затем воспользуемся UpdatePanel.
Будем выводить результаты поиска в обычный Repeater:
<asp:Repeater ID="lstResult" runat="server">
<ItemTemplate>
&
nbsp; <div>
&
nbsp; <a href='<%# Eval("URL") %>'>
<%#
Eval("Name")%>
&
nbsp; </a>
&
nbsp; </div>
</ItemTemplate>
</asp:Repeater>
В обычный серверный обработчик нажатия кнопки добавим следующий код:
protected void btnSearch_Click(object sender, EventArgs e)
{
lstResult.DataSource = GetSearchResult();
lstResult.DataBind();
}
Где GetSearchResult() – метод возвращающий результаты поиска.
Для того, чтобы убедиться, что форма перегрузилась целиком, добавим следующий код в класс формы:
public void Page_Load()
{
btnSearch.Attributes["onclick"] = "window.status='Поиск...'";
}
То есть, при нажатии на кнопку, в строку статуса браузера пропишется некое значение. Но так как страница целиком перегрузится, состояние строки статуса браузера утратиться. Запускаем и убеждаемся в этом:
Теперь изменим код нашей формы таким образом, чтобы Repeater, отображающий результаты поиска, оказался внутри UpdatePanel:
<atlas:UpdatePanel ID="pnlResults"
runat="server">
<ContentTemplate>
<asp:Repeater ID="lstResult"
runat="server">
…
</asp:Repeater>
</ContentTemplate>
</atlas:UpdatePanel>
Теперь укажем этому контролу, реакцией на какое событие на форме будет обновление панели. Для этого перейдем в режим дизайна формы и найдем свойство Triggers у UpdatePanel:
Нажав на кнопку редактирования свойства, мы попадаем в редактор триггеров:
Пока список пуст. Нажимаем "New Trigger":
В визарде создания триггера нам предлагается выбрать тип триггера: будет ли это реакция на конкретное событие контрола, или на изменение одного из его свойств. Нам нужен триггер, который бы реагировал на нажатие кнопки поиска. Для этого выбираем тип триггера "Trigger when a control raises an event", и выбираем во втором поле нашу кнопку и событие Click:
Завершаем редактирование и переходим в режим редактирования исходного кода формы. Мы увидим, что в тэга панели добавилась соответствующая секция:
<atlas:UpdatePanel ID="pnlResults"
runat="server">
…
<Triggers>
<atlas:ControlEventTrigger
ControlID="btnSearch" EventName="Click" />
</Triggers>
</atlas:UpdatePanel>
И, наконец, последнее действие. Мы должны установить свойство EnablePartialRendering у контрола ScriptManager в True:
<atlas:ScriptManager ID="scriptManager" runat="server"
EnablePartialRendering="True">
</atlas:ScriptManager>
Этим свойством вы укажете Atlas, что необходимо взять обработку всех постбэков на себя. Если вы забудете указать это свойство, то Atlas просто не будет знать, когда происходит постбэк и вся форма перегрузится целиком.
Все готово, можем запустить приложение и насладиться результатом:
Заключение
Стоит ли использовать Atlas сейчас в своих проектах? Каждый может решить это для себя сам. Важно только помнить, что каждый следующий релиз может поставлять не только исправления старых ошибок, но и радикально измененный дизайн библиотеки. Кроме того, текущая версия, как показывает опыт, устойчиво ведет себя только в основных вариантах использования. Если вы захотите большей гибкости, то готовьтесь столкнуться с кучей проблем.
Нужно отметить, то разработка Atlas идет с активным параллельным внедрением. Вы можете посмотреть, как Atlas используется на сайтах http://www.live.com/, http://www.start.com/, http://beta.msn.com/, http://microsoftgadgets.com/. Можно предположить, что релиз Atlas будет тогда же, когда будет релиз этих сайтов. Так же можно предположить, что Atlas вполне может быть встроен в ASP.NET версии, которая будет поставляться с новейшей версией .NET, который ожидается после релиза Vista. Ну а все эти взаимосвязи и проекты наводят на мысли, что Atlas является частью большого плана Microsoft по активному продвижению концепции "Web 2.0".
Что ж, нам остается наедятся, что результат этих трудов будет соответствовать заявленным планам.
P.S. В коде тестового сайта в реализации метода GetAutoCompleteList() использовался код из примера в одной из лабораторных работ по Atlas, которые вы можете найти на сайте проекта.