AJAX для ASP.NET и шаблоны на стороне клиента
ОГЛАВЛЕНИЕ
В сущности, настоящими приложениями AJAX являются те, которые используют для обхода обозревателя объект XMLHttpRequest и устанавливают прямую связь с веб-сервером и любыми размещенными конечными точками HTTP. Такие приложения способны асинхронно получать необходимые данные и независимо от этого обновлять нужные блоки интерфейса пользователя. Используя этот ключевой принцип, было разработано несколько сред AJAX, содержащих разные дозы «синтаксического сахара», большие или меньшие функциональные возможности, а также более или менее обширные наборы элементов управления для пользовательского интерфейса. Одна из таких сред — это AJAX для ASP.NET.
Спроектировать и собрать настоящее приложение AJAX непросто, тем более в отсутствие надлежащих средств программирования. По сравнению с другими платформами, AJAX для ASP.NET отличается хорошими возможностями доступа к коду на сервере. С точки зрения разработчика подключиться к поддерживающему сценарии веб-серверу или к службе Windows Communication Foundation (WCF) с помощью AJAX для ASP.NET — пустяковое дело. Нужно просто сослаться на URL-адрес, и платформа сама создаст класс прокси на языке JavaScript. Это просто и эффективно. Класс прокси скрывает все детали связей объекта XMLHttpRequest, сериализацию и десериализацию, форматы данных и пакетирование в HTTP. Нужно всего лишь вызвать метод асинхронно и получить обычный объект передачи данных (то есть DTO) с его собственным набором свойств.
Однако для обработки загруженных данных в обозревателе платформа AJAX для ASP.NET не предоставляет такого же удобного механизма. Без сомнения, этот недостаток будет вскоре исправлен, но пока в AJAX для ASP.NET нет такой же многофункциональной модели интерфейса пользователя для работы на стороне клиента, как модели служб для работы на стороне сервера.
Что же можно сделать для улучшения модели пользовательского интерфейса в настоящих веб-приложениях AJAX для ASP.NET? В прошлом месяце я познакомил вас с концепцией одностраничного интерфейса (Single-Page Interface, SPI) и с парой простых шаблонов проектирования, полезных при построении страниц SPI. Сегодня мы обсудим шаблоны на стороне клиента и привязку данных.
Типичная функция AJAX
Классической иллюстрацией возможностей подхода, предлагаемого AJAX, является приложение, которое выводит котировки акций в реальном времени. Веб-узлы, реализующие такую же функциональность без применения AJAX, используют тег метаобновления или решения, основанные на таких подключаемых модулях, как Flash, Silverlight™ или управляющие элементы ActiveX®. Обычно список величин котировок привязан на стороне сервера к управляющему элементу «сетка», который обновляется вместе с остальной страницей при каждой следующей обратной передаче или по запросу страницы. Такие страницы легко улучшаются внедрением частичной визуализации. Это можно сделать следующим образом: разметка, показанная на рис. 1, помещает управляющий элемент «сетка» в элемент UpdatePanel, который периодически обновляется с помощью управляющего элемента Timer.
Рис. 1 Пользовательский интерфейс страницы вывода котировок акций в реальном времени
<asp:UpdatePanel runat="server" ID="UpdatePanel1" UpdateMode="Conditional">
<ContentTemplate>
<div style="margin:10px;">
<asp:Label runat="server" ID="Label2" />
<asp:GridView ID="GridView1" runat="server" SkinID="ClassicGrid"
AutoGenerateColumns="false"
OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField DataField="Symbol" HeaderText="SYMBOL" />
<asp:BoundField DataField="Quote" HeaderText="LAST" >
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
<asp:BoundField DataField="Change" HeaderText="CHANGE" >
<ItemStyle HorizontalAlign="Right" />
</asp:BoundField>
</Columns>
</asp:GridView>
<small><asp:Label runat="server" ID="Label1" /></small>
</div>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" />
</Triggers>
</asp:UpdatePanel>
<asp:Timer runat="server" id="Timer1" Enabled="true"
Interval="600000" OnTick="Timer1_Tick" />
Управляющий элемент «сетка» привязан к коллекции объектов, обладающих как минимум тремя свойствами: биржевой код, котировка и ее изменение. Содержимое сетки обновляется каждые 10 минут. Управляющий элемент «таймер» платформы AJAX для ASP.NET активирует таймер на стороне клиента, а когда время ожидания заканчивается, вызывает обратную передачу. Поскольку сетка обернута элементом UpdatePanel, котировки в ней обновляются независимо от остальной страницы. На стороне сервера при каждом сигнале таймера исполняется следующий код:
protected void Timer1_Tick(object sender, EventArgs e)
{
Label2.Text = "<b>Last update: </b>" + DateTime.Now.ToLocalTime();
GridView1.DataSource = picker.Update();
GridView1.DataBind();
}
Объект «загрузчик» — это экземпляр пользовательского вспомогательного класса StockPicker. В этом классе находится экземпляр служебного класса, который получает данные котировок. Вот конструктор класса StockPicker:
public StockPicker(string stocks)
{
string provider = ConfigurationManager.AppSettings["StockProvider"];
_service = GetFactory(serviceProvider, stocks);
if (_service == null)
return;
_desc = _service.GetServiceDescription();
}
Загрузчик читает имя класса-поставщика данных из файла настроек и создает экземпляр этого класса. Его взаимодействие со служебным классом удовлетворяет контракту, представленному интерфейсом IQuoteService:
interface IQuoteService
{
StockInfoCollection GetQuotes();
string GetServiceDescription();
}
В образце кода, поставляемого с этой статьей, приведен имитатор службы выборки котировок, который в качестве значений котировок возвращает случайные числа. Однако код этой страницы легко настроить для использования настоящего поставщика котировок. Все, что нужно для этого сделать, — это создать класс, реализующий интерфейс IQuoteService, и подключиться к настоящему поставщику данных по акциям. В приведенном коде привязываемые данные представлены коллекцией объектов StockInfo:
public class StockInfo
{
public string Symbol { get; set; }
public string Quote { get; set; }
public string Change { get; set; }
public string Day { get; set; }
public string Time { get; set; }
}
На рис. 2 показан пример страницы AJAX для ASP.NET, основанной на этом интерфейсе API, в действии.
Рис. 2 Страница обновляемых котировок с использованием частичной визуализации
Ограничения частичной визуализации
С точки зрения функциональности страница, показанная на рис. 2, работает нормально. Если вас устраивает ее производительность и поведение — отлично. Однако существуют несколько стоящих упоминания недостатков работы этой страницы, хотя они и не вызовут у вас бессонницы.
Во-первых, при каждом обновлении этой страницы пересылается немалый объем данных. Объем данных не будет проблемой на странице, которая обновляется раз в 10 минут. С помощью Fiddler или Web Development Helper можно посмотреть объем передающихся данных, который составляет около 3 КБ при загрузке и немного меньше при отправке запроса. Опять же, если такие значения укладываются в ограничения вашей задачи, то используйте частичную визуализацию и дальше.
Однако если посмотреть на внутренние механизмы работы страницы, то эти значения становятся не такими уж безобидными. При каждом обновлении состояние представления страницы пересылается на сервер и обратно. В ответе сервера содержатся как данные, так и информация об их структуре. Более того, данные слиты с окружающей разметкой и не могут быть от нее отделены. Наконец, если на странице есть другие работающие панели с таким же механизмом обновления, то на какое-то таймер может быть остановлен другой запущенной операцией частичной визуализации, или же сработавший таймер может прервать выполнение уже начавшейся операции.
Таким образом, хоть программированию частичной визуализации можно быстро научиться, а саму ее несложно реализовать, это не лучший механизм поддержки нескольких асинхронных вызовов. Давайте посмотрим, как можно переписать страницу с рис. 2 с использованием чистого подхода AJAX.
Повторное рассмотрение динамической страницы котировок
Как изменится структура динамической страницы котировок при применении подхода, основанного на чистом AJAX? На странице установлен таймер, а для вызова удаленной службы используется XMLHttpRequest. Эта служба — часть серверного компонента приложения, она использует стандартный интерфейс API Microsoft® .NET Framework для вызова финансовой веб-службы и получения данных. Затем данные в виде объекта JavaScript возвращаются в обозреватель, где ваш код должен визуализировать их для пользователя.
В чем разница? Во-первых, вызываемый URL-адрес — это не сама страница. Страница вызывает конечную точку HTTP, реализованную с помощью поддерживающей сценарии веб-службы или службы WCF. Нет ни жизненного цикла страницы, ни событий обратного вызова, ни восстановления состояния представления. В результате существенно уменьшается сетевой трафик. Для этой простой страницы полезная нагрузка в 10 раз меньше, чем при частичной визуализации. С архитектурной точки зрения работающий код удалось разделить на два хорошо разделенных блока — интерфейсная часть на стороне клиента и серверная на стороне сервера. Первый работает на JavaScript; последний в управляемом коде.
Для таких задач особенно хороша платформа AJAX для ASP.NET, потому что с ее помощью можно унифицировать программный интерфейс и типы данных так, чтобы разработчик клиента на JavaScript использовал бы такие же интерфейс и контракты поведения, как и определенные на сервере. Объектная нотация (JavaScript Object Notation, JSON) гарантирует, что объекты DTO, прибывающие на клиента, точно соответствуют данным, переданным сервером.
Давайте немного поэкспериментируем с кодом. На новой странице есть кнопка, которую нажимает пользователь, когда хочет загрузить новые данные. Я использую эту кнопку вместо таймера только для удобства:
<input type="button" id="btnRefresh"
value="Live Quotes"
onclick="_getLiveQuotes()" />
Затем обработчик JavaScript вызывает метод класса-обертки веб-службы котировок и получает коллекцию объектов StockInfo:
<%@ WebService Class="Samples.WebServices.LiveQuoteService" %>
Полный исходный код для службы показан на рис. 3.
Рис. 3 Веб-служба динамических данных по котировкам
namespace Samples.WebServices
{
[WebService(Namespace = "http://samples.ajax/")]
[ScriptService]
public class LiveQuoteService : System.Web.Services.WebService
{
private static string stocks =
ConfigurationManager.AppSettings["StockSymbols"];
private static StockPicker picker = new StockPicker(stocks);
public LiveQuoteService()
{
}
[WebMethod]
public StockInfoCollection Update()
{
return picker.Update();
}
[WebMethod]
public string GetServiceDescription()
{
return picker.GetServiceDescription();
}
}
}
В случае частичной визуализации нет естественного разделения элементов интерфейса пользователя (представления) и основной логики приложения (модели). Все собирается на сервере и в готовом виде отправляется клиенту. Настоящая архитектура AJAX предполагает, что уровень представления более интеллектуален и функционален, чем уровень бизнес-логики, и что эти два уровня физически разделены. Безусловно, архитектура с такой высокой изоляцией является намного более гибкой и лучше тестируется. Кроме того, появляется больше возможностей для кэширования данных, как показано на рис. 4.
Рис. 4 Возможные уровни кэширования в архитектуре AJAX
Данные могут кэшироваться на сервере, средствами пользовательского интерфейса поддержки и реализации (веб) службы. Кроме того, данные могут кэшироваться на пути к клиенту с помощью прокси HTTP или даже кодом JavaScript, исполняемом в обозревателе. Более важно то, что не кэшируется разметка; кэшируются только полезные данные (объекты или строки JSON), которые в любое время можно проверить на выполнение любых условий времени исполнения.
Также полезен и перенос логики визуализации на клиента, поскольку это облегчает работу и без того загруженного сервера. Если серверу приходится возвращать только небольшие блоки данных вместо того, чтобы исполнять полный жизненный цикл страницы с созданием разметки и обработкой состояния представления, то можно сэкономить загрузку ЦП и память.
Так же просто использовать AJAX для ASP.NET со стороны клиента, чтобы взаимодействовать с удаленными службами и выбирать данные в обозреватель. Например, следующий код вызывает удаленный метод:
function _getLiveQuotes()
{
Samples.WebServices.LiveQuoteService.Update(onDataAvailable);
}
function onDataAvailable(results)
{
// Update the UI
}
AJAX для ASP.NET предоставляет объект прокси JavaScript с тем же именем, что и службы на стороне сервера, а также несколько статических методов. В приведенном примере кода метод Update выбирает весь массив определения типов документов (DTD) на JavaScript и передает его функции обратного вызова, ответственной за обновление интерфейса пользователя. Переменная «results» в коде содержит ответ службы — как раз те данные, которые нужно привязать к таблице.
К сожалению, на стороне клиента нет элемента управления GridView, как при использовании ASP.NET на стороне сервера. Требуется способ привязки данных на стороне клиента, желательно с какими-то возможностями поддержки шаблонов. Пока платформа AJAX для ASP.NET не особенно может в этом помочь. Дальнейшее объяснение этого вопроса непосредственно от рабочей группы Microsoft ASP.NET находится на врезке «Дополнительные сведения: AJAX для ASP.NET»
Недавно некоторые крупные поставщики управляющих элементов ASP.NET начали предлагать серверные элементы управления с эквивалентной объектной моделью на стороне клиента. Если вы используете какую-либо из этих библиотек, то у вас в руках могут оказаться объекты JavaScript, воспроизводящие поведение серверных элементов управления, а также имеющие клиентское свойство Data source и метод DataBind. Платформа AJAX для ASP.NET предоставляет функцию автоматического создания контроллера по модели, необходимую для вызова веб-службы из клиента, но не полную платформу для разработки пользовательского интерфейса, ориентированную на AJAX; не предоставляет он и средств клиентских средств работы с шаблонами и привязки данных. Интересный материал по различным подходам к построению интерфейса пользователя с использованием AJAX представлен сообщением Мильяна Братицевича (Miljan Braticevic) на go.microsoft.com/fwlink/?LinkID=116054.
Шаблоны на стороне клиента в AJAX для ASP.NET
Помните «Atlas»? В ранних сборках того, что позже стало «расширениями AJAX для ASP.NET», была сделана попытка реализовать шаблоны и привязку данных на стороне клиента. Причем очень неплохая попытка. Однако по некоторым причинам в окончательный выпуск этот вариант не вошел и был передвинут в библиотеку Futures в ASP.NET.
В сущности, старая модель привязки данных Atlas основывалась на шаблонах и декларативном синтаксисе, выражающем привязку между элементами разметки и полями данных. Затем шаблоны и привязка объединялись в управляющем элементе на стороне клиента — элементе List view («представление в виде списка»). Настраиваемый через XML, элемент ListView библиотеки Atlas выполнял большое количество работы по синтаксическому разбору всей получаемой информации и был способен присоединять поведение, элементы управления и данные к разным частям разметки.
Рассмотрим начиная с этого последнего пункта способы, с помощью которых можно построить свою небольшую, но эффективную платформу привязок и шаблонов. Обратите внимание, что в конце концов должна получиться строка с разметкой HTML. Начальными данными является коллекция объектов с несколькими общедоступными свойствами. Задача программиста — построить такой фрагмент кода HTML, который соответствовал бы ожиданиям пользователя. Начинать, в общем, надо с обхода коллекции объектов с привязанными данными и соединением текста шаблона с величинами свойств объектов.
Что не так в этом подходе? Вообще-то ничего. В сущности, я не могу придумать какого-то радикально отличающегося от этого подхода, который не делал бы в какой-то момент точно такой же перебор данных. А значит, наверняка можно создать платформу, в которой эта цикл будет основной абстрактной процедурой. В каталоге шаблонов проектирования AJAX (см. www.ajaxpatterns.org) ключевые этапы создания модели обработки шаблонов на стороне клиента находятся под названием «Применение шаблонов на стороне обозревателя» (BST).
Прием проектирования: применение шаблонов на стороне обозревателя
Цель применения шаблона проектирования BST в том, чтобы отделить код, создающий представления данных, от самих данных. Будучи старой проблемой программных систем, отделение представления от данных имеет классическое решение: любую разновидность шаблона проектирования Model View Controller (MVC).
Хотя применение приемов проектирования MVC и BST ни в коем случае не является взаимоисключающим, BST можно рассматривать как MVC, в котором нет никаких упоминаний о котроллере и в котором разделение между представлением и моделью осуществляется с помощью физического разделения обозревателя и сервера. На рис. 5можно посмотреть диаграмму стадий, входящих в BST. Пользователь вызывает удаленный вызов, который загружает какие-то данные на клиента. Данные управляются функцией обратного вызова JavaScript, которая создает новое поколение компонент — построители разметки.
Рис. 5 Шаблоны на стороне обозревателя в действии
Построитель разметки возвращает строку HTML, используя при ее построении один или несколько шаблонов HTML на странице в объектной модели документа (модели DOM) и загруженные данные. Наконец, функция встраивает полученную строку в DOM страницы.
Теперь посмотрим на код. В этой реализации основная логика BST находится в JavaScript-классе MarkupBuilder, который принимает до трех HTML-шаблонов: верхний колонтитул, нижний колонтитул и элемент. К этим шаблонам можно напрямую обратиться из модели DOM или указать их как обычные текстовые строки:
function pageLoad()
{
if (builder === null)
{
builder = new Samples.MarkupBuilder();
builder.loadHeader($get("header"));
builder.loadFooter($get("footer"));
builder.loadItemTemplate($get("item"));
}
}
C помощью невидимых DIV HTML-шаблоны можно встраивать прямо в страницу. Правда, это работает только тогда, когда у разметки блока правильный формат. Лучше встраивать шаблоны в островки данных XML, как показано здесь:
<xml id="item">
<tr style="background-color:#F0FAFF;">
<td align="left">#Symbol</td>
<td align="right">#Quote</td>
<td align="right">#Change</td>
</tr>
</xml>
Как можно заметить, шаблон – это блок HTML, который ссылается на привязанные поля данных с помощью выбранной нотации. В данном случае я воспользовался выражением #PropertyName, чтобы указать на местозаполнитель для привязанного значения. Когда данные готовы, остается только вызвать метод bind для построителя разметки:
function _getLiveQuotes()
{
Samples.WebServices.LiveQuoteService.Update(onDataAvailable);
}
function onDataAvailable(results)
{
var temp = builder.bind(results);
$get("grid").innerHTML = temp;
}
Незачем и упоминать, что именованная сетка элементов является местозаполнителем всего вывода данных в этом примере. Класс MarkupBuilder основан на клиентской библиотеке Microsoft AJAX. Его полный исходный код доступен на рис. 6.
Рис. 6 класс MarkupBuilder
Type.registerNamespace('Samples');
// Class ctor
Samples.MarkupBuilder = function Samples$MarkupBuilder()
{
Samples.MarkupBuilder.initializeBase(this);
// Initializes private members
this._header = "";
this._footer = "";
this._itemTemplate = "";
}
Samples.MarkupBuilder = function Samples$MarkupBuilder(header, footer)
{
Samples.MarkupBuilder.initializeBase(this);
// Initializes the private members
this._header = header;
this._footer = footer;
this._itemTemplate = "";
}
// PROPERTY:: header (String)
function Samples$MarkupBuilder$get_header() {
if (arguments.length !== 0) throw Error.parameterCount();
return this._header;
}
function Samples$MarkupBuilder$set_header(value) {
var e = Function._validateParams(arguments, [{name: 'value',
type: String}]);
if (e) throw e;
this._header = value;
}
// PROPERTY:: footer (String)
function Samples$MarkupBuilder$get_footer() {
if (arguments.length !== 0) throw Error.parameterCount();
return this._footer;
}
function Samples$MarkupBuilder$set_footer(value) {
var e = Function._validateParams(arguments, [{name: 'value',
type: String}]);
if (e) throw e;
this._footer = value;
}
// PROPERTY:: itemTemplate (String)
function Samples$MarkupBuilder$get_itemTemplate() {
if (arguments.length !== 0) throw Error.parameterCount();
return this._itemTemplate;
}
function Samples$MarkupBuilder$set_itemTemplate(value) {
var e = Function._validateParams(arguments, [{name: 'value',
type: String}]);
if (e) throw e;
this._itemTemplate = value;
}
// METHOD:: bind()
function Samples$MarkupBuilder$bind(data) {
var temp = this._generate(data);
return temp;
}
// METHOD:: loadHeader()
function Samples$MarkupBuilder$loadHeader(domElement) {
var temp = domElement.innerHTML;
this._header = temp;
}
// METHOD:: loadFooter()
function Samples$MarkupBuilder$loadFooter(domElement) {
var temp = domElement.innerHTML;
this._footer = temp;
}
// METHOD:: loadItemTemplate()
function Samples$MarkupBuilder$loadItemTemplate(domElement) {
var temp = domElement.innerHTML;
this._itemTemplate = temp;
}
/////// ///////
/////// PRIVATE members ///////
/////// ///////
function Samples$MarkupBuilder$_generate(data) {
var _builder = new Sys.StringBuilder(this._header);
for(i=0; i<data.length; i++)
{
var dataItem = data[i];
var template = this._itemTemplate;
var pattern = /#\w+/g; // Finds all #word occurrences
var matches = template.match(pattern);
for (j=0; j<matches.length; j++)
{
var name = matches[j];
name = name.slice(1);
template = template.replace(matches[j], dataItem[name]);
}
_builder.append(template);
}
_builder.append(this._footer);
return _builder.toString();
}
// PROTOTYPE
Samples.MarkupBuilder.prototype =
{
get_header: Samples$MarkupBuilder$get_header,
set_header: Samples$MarkupBuilder$set_header,
get_footer: Samples$MarkupBuilder$get_footer,
set_footer: Samples$MarkupBuilder$set_footer,
get_itemTemplate: Samples$MarkupBuilder$get_itemTemplate,
set_itemTemplate: Samples$MarkupBuilder$set_itemTemplate,
bind: Samples$MarkupBuilder$bind,
_generate: Samples$MarkupBuilder$_generate,
loadHeader: Samples$MarkupBuilder$loadHeader,
loadFooter: Samples$MarkupBuilder$loadFooter,
loadItemTemplate: Samples$MarkupBuilder$loadItemTemplate
}
Samples.MarkupBuilder.registerClass('Samples.MarkupBuilder');
Для составления строки HTML внутри построителя разметки используется объект Sys.StringBuilder. Сначала он добавляет шаблон заголовка (если он есть), затем выполняет цикл по связанным данным и в конце добавляет шаблон нижнего колонтитула. В этой реализации верхний и нижний колонтитулы не связаны с данными. (На рис. 7 показана страница, использующая построитель разметки.)
Рис. 7 Новая страница, составленная с помощью построителя разметки
Дальнейшие перспективы
Есть ли разница между указанием шаблона в виде обычной строки и в качестве встроенного поддерева DOM или острова данных XML? С точки зрения построителя разметки никакой разницы нет — всё, что необходимо, это чтобы строка присоединялась к буферу составителя строк С точки зрения разработчика, возможно, лучше использовать шаблоны DOM — их легко проверить, а также можно загружать по URL-адресу.
Хотя представленное здесь решение разработано для работы только с коллекциями данных, оно следует принципам проектирования, применяемым в свободно распространяемых платформах для работы с шаблонами на стороне клиента. Одна из таких сред, которую мне хотелось бы упомянуть особо, это PrototypeJS. Дополнительная информация, примеры и исходный код находятся на странице prototypejs.org/api/template.
Можно ли улучшить что-нибудь еще? Конечно! Обратите внимание, что код, приведенный в этой статье, реализует только минимальный набор функций, которые можно ожидать от подсистемы шаблонов и привязки данных на стороне обозревателя.
Как видно на рис. 7, в данной реализации отсутствует возможность различать цены растущих и падающих акций по цвету, как в варианте на рис. 2. В коде с рис. 2 событие RowDataBound элемента управления GridView обрабатывается самим кодом приложения, и стили затронутых клеток меняются напрямую:
void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.Cells[2].Text.StartsWith("+"))
e.Row.Cells[2].ForeColor = Color.Green;
if (e.Row.Cells[2].Text.StartsWith("-"))
e.Row.Cells[2].ForeColor = Color.Red;
}
В решении, связанном с частичной визуализацией, предполагается, что все эти действия со стилями выполняются на сервере и, следовательно, могут использовать полнофункциональную модель программирования связанных с данными элементов управления на сервере. Чтобы добиться того же на стороне клиента, требуется более сложный построитель разметки, который мог бы принимать делегат функции, который и назначал бы стили каждому блоку связанных данных перед тем, как они попадут в буфер.
Есть и еще одно важное различие между примерами кода с рис. 2 и 7, которого не видно за напечатанными числами. Чтобы найти это отличие, попробуйте запустить обе страницы и нажать на другие видимые кнопки («прогнозы погоды» и «запустить задание»). Страница, показанная на рис. 7, не останавливает другие задания на время извлечения котировок акций, а ее собственный вызов службы на сервере не прерывается запуском какого-то другого задания.
В чем причина? Помните, что в варианте с частичной визуализацией в одно и то же время в одном и том же сеансе мог работать только один запрос — точно так же, как и на странице, где AJAX не используется. Конечно же, если работать прямо через XMLHttpRequest, одновременно работающих вызовов может быть сколько угодно. Более того, если вызывать службы напрямую, то не нужно следить за состоянием представления и за тем, останется ли оно согласованным после нескольких запросов на частичную визуализацию (это и есть главная причина того, что частичная визуализация не дает выполнять операции параллельно).
Прием проектирования: сообщение HTML
Чтобы завершить эту статью, я сделаю краткий комментарий по поводу другого приема проектирования, который для обсуждения заслуживает отдельной статьи — он называется «шаблон проектирования – сообщение HTML. Цель этого приема в том, чтобы блоки разметки HTML, показываемые в обозревателе, создавались на сервере. Как видите, это промежуточный подход между частичной визуализацией и другими моделями построения настоящих приложений AJAX.
Как можно использовать этот прием? Одним из примеров применения может быть вызов по удаленному URL-aдресу (службы или отдельного обработчика HTTP) и получение готового к показу фрагмента кода HTML. Заметьте, что трафика создается больше, чем при обычном вызове службы, но меньше, чем при частичной визуализации.
На сервере можно использовать свежие экземпляры управляющих элементов (без состояния просмотра), чтобы собрать любую нужную выдачу и наложить на нее стили. Я вернусь к этому приему в будущей статье.
Помните, что если вы работаете с AJAX для ASP.NET, необходимо программное средство, которое определяло бы уровень обслуживания AJAX вызывало бы его из клиентского обозревателя. Вдобавок, нужно универсальное средство для того, чтобы эффективно менять данные на клиенте, такое как основанный на JavaScript язык обработки данных и шаблонов.
Надеюсь, что когда вы будете смотреть на реализацию шаблона проектирования AJAX BST, которую я описал в этой статье и сравнил его с частичной визуализацией, вы неизбежно придете к тем же выводам, что и я.
Скачать исходники примеров кода
Автор: Дино Эспозито
Источник: http://msdn.microsoft.com/ru-ru/magazine/