Programmirovanie V Aspnet Ajax
Programmirovanie V Aspnet Ajax
Co
Ра ы C res
Создай пользовательский интерфейс
ке utu
r
сс on CT
т
в стиле Web 2.0 с помощью ASP.NET AJAX
мо tro P и
тр l To д
ен o ру
Программирование в ASP.NET AJAX
ы lkit гие
Это издание является полным практическим введением в новую платформу
,
Microsoft ASP.NET AJAX 1.0, которая предоставляет большие преимущества при
Программирование в
ASP.NET AJAX
Программирование в
разработке Ajax-приложений, схожие с теми, которые дает ASP.NET для разработ-
ки серверных сценариев. Из книги «Программирование в ASP.NET AJAX» вы узнае-
те, как с помощью технологий Ajax без особых затрат времени создавать профес-
сионально выполненные динамические веб-страницы.
ASP.NET
Насыщенная примерами, демонстрирующими ключевые аспекты платформы, эта книга иде-
ально подходит не только разработчикам ASP.NET, стремящимся расширить свои возможно-
сти за счет использования Ajax, но и всем специалистам, кто интересуется данной платфор-
мой, независимо от того, какие технологии они используют в настоящее время.
Книга «Программирование в ASP.NET AJAX» предлагает вашему вниманию:
• Обзор платформы ASP.NET AJAX
• Функциональный программный код, который можно вставлять в собственные приложения
AJAX
• Описание основ JavaScript и Ajax с целью помочь разобраться в отдельных технологиях, ис-
пользуемых платформой
• Содержимое и организацию составляющих частей платформы, включая пакеты Extensions,
Control Toolkit, Futures CTP и AJAX Library
• Инструкции по созданию собственных элементов управления и оказанию содействия со-
обществу пользователей и разработчиков пакета Control Toolkit
• Способы использования стандартизированной библиотеки AJAX Library с другими плат-
формами, такими как PHP
• Исчерпывающая глава об элементе управления UpdatePanel – одном из самых важных эле-
ментов платформы, который позволяет организовать независимое обновление отдельных
частей веб-страницы
Первое издание этой книги был выпущено под названием «Programming Atlas» с обзором бета-
версии платформы компании Microsoft. Настоящее издание полностью обновлено и дополне-
но и содержит описание официальной версии ASP.NET AJAX 1.0. В книгу включено множество
подробностей, которые трудно найти в документации, а также оригинальные способы реше-
ния некоторых задач. Это идеальный источник информации о новой платформе.
Кристиан Венц (Christian Wenz) – преподаватель и консультант, автор более 50 книг.
В своей работе он использует как коммерческие веб-технологии, так и распространяемые
с открытыми исходными текстами. Компания Microsoft удостоила его чести быть занесен-
ным в список MVP (Most Valuable Professionals – наиболее значимые специалисты) для ASP/
ASP.NET. Кристиана Венца также можно найти в списке «Who’s Who of PHP» компании Zend
и в спис ке участников проекта Mozilla (about:credits). Кроме того, Кристиан – признанный
эксперт по клиентскому JavaScript.
Christian Wenz
Программирование
в ASP.NET AJAX
Кристиан Венц
СанктПетербург–Москва
2008
Кристиан Венц
Программирование в ASP.NET AJAX
Перевод А. Киселева
Главный редактор А. Галунов
Зав. редакцией Н. Макарова
Научный редактор Б. Попов
Редактор Ю. Бочина
Корректор C. Минин
Верстка Д. Орлова
Венц К.
Программирование в ASP.NET AJAX. – Пер. с англ. – СПб: СимволПлюс,
2008. – 512 с., ил.
ISBN13: 9785932861226
ISBN10: 5932861223
Книга Кристиана Венца «Программирование в ASP.NET AJAX» – полное прак
тическое введение в новую платформу Microsoft ASP.NET AJAX 1.0, которая
предоставляет большие преимущества при разработке Ajaxприложений, схо
жие с теми, которые дает ASP.NET для разработки серверных сценариев. Вы
узнаете, как с помощью технологий Ajax без особых затрат времени создавать
профессионально выполненные динамические вебстраницы.
После общего обзора платформы и основ JavaScript и Ajax рассмотрена органи
зация составляющих частей .NET, включая пакеты Extensions, Control Toolkit,
Futures CTP и Microsoft AJAX Library. Также читателю предлагается исчерпы
вающая глава об элементе управления UpdatePanel, который позволяет орга
низовать независимое обновление отдельных частей вебстраницы.
Насыщенная примерами, демонстрирующими ключевые аспекты платформы,
эта книга идеально подходит не только разработчикам ASP.NET, стремящим
ся расширить свои возможности за счет использования Ajax, но и всем специ
алистам, кто интересуется данной платформой, независимо от того, какие тех
нологии они используют в настоящее время.
ISBN13: 9785932861226
ISBN10: 5932861223
ISBN 0596514247 (англ)
Предисловие . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
I. Основы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1. ASP.NET AJAX, Ajax и ASP.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
ASP.NET AJAX и Ajax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
ASP.NET AJAX и ASP.NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Подготовка и установка ASP.NET AJAX . . . . . . . . . . . . . . . . . . . . . . . . . 28
Структура и архитектура ASP.NET AJAX . . . . . . . . . . . . . . . . . . . . . . . . 34
Первый пример ASP.NET AJAX: Hello User . . . . . . . . . . . . . . . . . . . . . . 35
Элемент управления ScriptManager. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Подведение итогов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Для дополнительного чтения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2. JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Язык программирования JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Объектноориентированное программирование (ООП) . . . . . . . . . . . . . 57
Доступ к элементам страницы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Методы DOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
Подведение итогов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Для дополнительного чтения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3. Ajax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Объект XMLHttpRequest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Объект XMLDocument . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
Подведение итогов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Для дополнительного чтения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Объектноориентированные
возможности JavaScript в ASP.NET AJAX . . . . . . . . . . . . . . . . . . . . . . . 97
Клиентские версии классов .NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Подведение итогов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Для дополнительного чтения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
5. Вебслужбы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Обработка ошибок . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Методы страницы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Управление состоянием сеанса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Обмен данными со сложной структурой . . . . . . . . . . . . . . . . . . . . . . . . . 130
Доступ к вебслужбам из JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
Подведение итогов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Для дополнительного чтения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Технические требования
Для опробования примеров из этой книги необходимо и достаточно
иметь платформу ASP.NET 2.0, которая включена в состав свободно
распространяемой платформы .NET. Однако, чтобы получить макси
мум от использования ASP.NET и ASP.NET AJAX, вам необходимо
иметь какуюлибо интегрированную среду разработки из предлагае
мых компанией Microsoft. Среда Visual Web Developer 2005 Express
Edition (VWD) распространяется бесплатно. Visual Studio 2005 (любые
ее редакции) – пакет программного обеспечения, который обладает бо
гатыми возможностями, распространяется на коммерческой основе.
Любой из упомянутых инструментов прекрасно подойдет для опробо
вания примеров из этой книги.
Типографские соглашения
В этой книге приняты следующие соглашения:
Обычный шрифт
Применяется для обозначения пунктов меню, кнопок и комбина
ций клавиш (таких как Alt и Ctrl).
Курсив
Обозначает новые термины, адреса электронной почты и вебсай
тов, имена файлов и каталогов, расширений имен файлов, а также
названия утилит Unix.
Моноширинный шрифт
Применяется для выделения команд, параметров, ключей, перемен
ных, атрибутов, имен функций, типов, классов, пространств имен,
методов, модулей, свойств, аргументов, значений, объектов, собы
тий, обработчиков событий, тегов XML, тегов HTML, макроопреде
лений, содержимого файлов и результатов работы команд.
Моноширинный жирный
Используется для выделения участков программного кода.
Моноширинный курсив
Используется для выделения элементов, которые необходимо заме
нить на реальные значения.
Предисловие 17
Отзывы и предложения
С вопросами и предложениями, касающимися этой книги, обращай
тесь в издательство:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
8009989938 (в Соединенных Штатах Америки или в Канаде)
7078290515 (международный)
7078290104 (факс)
18 Предисловие
Благодарности
(к книге «Programming ASP.NET AJAX»)
Иногда оказывается так, что вы просто неудачно выбрали время. Спус
тя приблизительно две недели после выхода в свет первого издания
книги под названием «Programming Atlas» компания Microsoft изме
нила название платформы на ASP.NET AJAX. Неудачность выбора
времени обусловлена не только изменением названия – в Microsoft
также весьма радикально изменили внутреннюю архитектуру плат
формы. Как следствие этого – все примеры программного кода для At
las оказались неработоспособными в ASP.NET AJAX. Следует при
знать, что переписать большую часть примеров не составило большого
труда, но некоторые функциональные возможности платформы были
утрачены или изменены до неузнаваемости.
Вследствие этого данное издание книги полностью отличается от преды
дущего. Структура книги претерпела существенные изменения: в нее
было добавлено большое число новых глав, какойто материал был до
бавлен, какойто пришлось выбросить, а некоторые главы были полно
стью переписаны. Таким образом, хотя технически это второе издание –
это более или менее новая книга. Однако если у вас имеется программ
ный код, основанный на особенностях платформы Atlas, не волнуйтесь:
в нескольких главах этой книги вы найдете рекомендации по переносу
устаревшего программного кода на новую версию платформы.
Я выражаю благодарность моему редактору Джону Осборну (John Os
born), который руководил проектом, постоянно высказывая новые
20 Предисловие
Рис. 1.4. В .NET Framework 3.5 для проектов по созданию новых вебсайтов
автоматически используется ASP.NET AJAX
32 Глава 1. ASP.NET AJAX, Ajax и ASP.NET
Рис. 1.6. Подключение MDFфайла к серверу SQL Server 2005 Express Edition
Client Server
Текст разметки (HTML, CSS) (1) Запрос страницы (.aspx) Программный код ASP.NET
(2) Отправка страницы (HTML)
Сценарий (JavaScript, DOM) Вебслужба
(3) XMLHttpRequest
ASP.NET AJAX ASP.NET AJAX
Framework (клиент) (4) Отправка текста/XML Framework (сервер)
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
</div>
</form>
</body>
</html>
Первое, на что следует обратить внимание, – это новый элемент управ
ления: <asp:ScriptManager>. Этот элемент управления является основой
любой вебстраницы с поддержкой ASP.NET AJAX. Элемент Script
Manager будет рассмотрен гораздо подробнее ниже, в этой же главе
(раздел «Элемент управления ScriptManager»).
Откройте файл Default.aspx в текстовом редакторе и добавьте в эле
мент ScriptManager ссылку на вебслужбу, как показано ниже. При за
пуске страницы благодаря этой ссылке будет сгенерирован объектпо
средник JavaScript, с помощью которого страница будет способна ис
пользовать программный код, динамически сгенерированный про
граммным кодом вебслужбы:
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="WebService.asmx" />
</Services>
</asp:ScriptManager>
<title>ASP.NET AJAX</title>
<script language="Javascript" type="text/javascript">
function callService(f) {
WebService.sayHello(
f.elements["name"].value,
callComplete,
callError);
}
function callComplete(result) {
window.alert(result);
}
function callError(result) {
window.alert("Error! " + result);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager
ID="ScriptManager1"
runat="server">
<Services>
<asp:ServiceReference Path="WebService.asmx" />
</Services>
</asp:ScriptManager>
<div>
<input type="text" id="name" name="name" />
<input type="button" value="Call Service"
onclick="callService(this.form);" />
</div>
</form>
</body>
</html>
На рис. 1.9 показан внешний вид страницы после того, как она будет
загружена и пользователь щелкнет на кнопке Call Service.
Запустите приложение (клавишей F5 или Ctrl+F5 в VWD). В окне бро
узера можно увидеть вполне предсказуемый результат, причем не
только в Internet Explorer, но и в любом другом броузере, отвечающем
нашим требованиям. Щелкните на кнопке несколько раз и убедитесь,
что обновления страницы не происходит, хотя страница выполняет об
мен данными с вебслужбой на стороне сервера.
</Scripts>
</asp:ScriptManagerProxy>
Элемент ScriptManagerProxy удобно использовать при создании пользо
вательских элементов управления, обладающих функциональностью
AJAX, когда на главной странице уже присутствует элемент Script
Manager.
Это был лишь первый шаг. А сколько всего откроется в следующих
главах!
Подведение итогов
Эта глава – введение в платформу ASP.NET AJAX; в ней мы рассказа
ли о том, какое отношение эта платформа имеет к Ajax и ASP.NET 2.0,
и провели вас через процесс установки ASP.NET AJAX и другого про
граммного обеспечения, необходимого для опробования примеров из
этой книги, включая базу данных AdventureWorks. Здесь, кроме того,
был представлен первый работающий пример ASP.NET AJAX и эле
мент управления ScriptManager – один из двух ключевых серверных
элементов управления, которые входят в состав ASP.NET AJAX.
В следующей главе будет рассматриваться язык программирования
JavaScript, знание которого потребуется вам при работе с платформой
ASP.NET AJAX.
Переменные
Объявление переменных в JavaScript производится с помощью ключе
вого слова var. Совершенно необязательно следовать соглашениям об
именовании переменных, таким как использование префиксов, опре
деляющих типы переменных, как это принято в других языках, таких
как Perl или PHP. Все переменные имеют глобальную область видимо
сти, если они объявляются за пределами функций. Переменные не
привязаны жестко к определенному типу данных, что позволяет изме
нять их тип во время исполнения. Тем не менее в JavaScript имеется
несколько встроенных типов данных1, включая следующие четыре,
которые вы будете использовать неоднократно:
• Number (1, 2, 3.14159)
• String ("Hello", 'World')
• Boolean (true, false)
• RegEx (/d+/)
Массивы
Массив – это переменная, содержащая последовательность значений.
Так как JavaScript не является строго типизированным языком, мас
сив может одновременно хранить данные разных типов. Создать мас
сив можно двумя способами. Один из них заключается в использова
нии конструкции new Array(), в которой указывается несколько значе
ний. Индексация массивов начинается с нуля, таким образом, в сле
дующем фрагменте в массив добавляется седьмой элемент:
var days = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday");
days[6] = "Saturday";
Современные броузеры предлагают альтернативную, более краткую
форму определения массива, как показано ниже:
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday"];
Управляющие конструкции
Язык JavaScript поддерживает стандартный набор управляющих кон
струкций, включая switch, if...else и различные конструкции циклов
(for, for...in, foreach, while, do...loop и do...until). Начнем с инструк
ции if. Пример 2.2 генерирует случайные числа с помощью Math.ran
dom() (этой возможностью мы воспользуемся в этой книге снова). Эта
50 Глава 2. JavaScript
Операторы сравнения
Оператор == проверяет равенство операндов (в отличие от оператора
=, который выполняет операцию присваивания); из других операто
ров сравнения имеются >=, >, <, <= и !=. Особое значение имеет опе
ратор ===, который не только сравнивает значения операндов, но их
типы; отрицательная форма этого оператора записывается как !==.
JavaScript поддерживает терциальный (трехместный) оператор, кото
рый удобно использовать в качестве сокращенной формы записи кон
струкции if...else. Следующее выражение
var output = (rand % 2 == 1) ? "odd" : "even";
эквивалентно такой форме записи:
if (rand % 2 == 1) {
var output = "odd";
} else {
var output = "even";
}
Вместо последовательности операторов if для проверки одного и того
же выражения на равенство нескольким значениям можно воспользо
ваться инструкцией switch. Пример 2.3 демонстрирует, как это сделать.
Пример 2.3. Использование инструкции switch
JavaScript switch.htm
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JavaScript</title>
<script language="JavaScript" type="text/javascript">
var rand = Math.random();
rand = Math.ceil(6 * rand);
switch (rand) {
case 1:
case 3:
case 5:
document.write("Odd number: ");
break;
default:
document.write("Even number: ");
}
document.write(rand);
</script>
</head>
<body>
</body>
</html>
52 Глава 2. JavaScript
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JavaScript</title>
<script language="JavaScript" type="text/javascript">
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"];
var i = 0;
while (i < days.length) {
document.write(days[i] + "<br />");
i++;
}
</script>
</head>
<body>
</body>
</html>
</head>
<body>
<script language="JavaScript" type="text/javascript">
function HtmlEscape(s) {
var result = s.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
return result;
}
document.write(HtmlEscape("<hr />"));
</script>
</body>
</html>
В результате исполнения этого сценария будет выведена строка <hr
/>, которая будет отображаться броузером как <hr />, но не будет
приводить к выводу горизонтальной линии.
Язык JavaScript не поддерживает возможность перегрузки функций;
он не фиксирует число их аргументов. Если функции передать число
аргументов меньшее, чем было указано при ее объявлении, недостаю
щие аргументы внутри функции получат значение null.
При этом, как демонстрирует пример 2.8, если функции передается
большее число аргументов, чем было предусмотрено, доступ к избы
точным аргументам можно получить с помощью свойства arguments
(сокращенно от <ИмяФункции>.arguments).
Пример 2.8. Создание собственной функции с переменным числом аргументов
JavaScript function arguments.htm
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JavaScript</title>
</head>
<body>
<script language="JavaScript" type="text/javascript">
function OutputList() {
document.write("<ul>");
for (var i=0; i < arguments.length; i++) {
document.write("<li>" +
arguments[i] +
"</li>");
}
document.write("</ul>");
}
OutputList("one", "two", "three");
</script>
56 Глава 2. JavaScript
</body>
</html>
Результат работы сценария приводится на рис. 2.4.
Объектноориентированное
программирование (ООП)
JavaScript – это язык, основанный на объектах, но он не является объ
ектноориентированным (ООП) языком. В JavaScript есть некоторые
аспекты, напоминающие ООП, но поддержка возможностей, обычных
для ООП, весьма ограничена. Например, область видимости членов
класса (public, private, protected и прочие) может быть реализована
с существенными ограничениями. Однако в JavaScript есть возмож
ность создавать классы и даже имеется рудиментарная поддержка ме
ханизма наследования.
Классы в JavaScript реализуются в виде функций. Программный код
внутри этих функций – это реализация конструктора класса. Она
должна содержать объявления и определения всех элементов экземп
ляров (то есть всех общедоступных и частных свойств и методов). Для
ссылки на текущий экземпляр класса можно использовать ключевое
слово this, благодаря чему конструктор – и методы класса – получают
доступ к свойствам текущего класса. Точно так же программный код
класса имеет возможность присваивать свойства значениям и опреде
лять методы, которые затем будут доступны из программного кода за
пределами класса.
В примере 2.9 показан простой класс, который реализует абстракцию
книги. Обратите внимание: нами предусмотрено хранение данных
в частных свойствах класса, которые недоступны извне класса. Далее,
мы определяем общедоступные методы чтения и записи для доступа
к этим свойствам. Такой прием называется инкапсуляцией и позволя
ет унифицировать доступ к свойствам и организовать проверку значе
ний до того, как они будут записаны в свойства.
58 Глава 2. JavaScript
this.get_isbn = function() {
return _isbn;
}
this.set_isbn = function(value) {
_isbn = value;
}
this.get_author = function() {
return _author;
}
this.set_author = function(value) {
_author = value;
}
this.get_title = function() {
return _title;
}
this.set_title = function(value) {
_title = value;
}
this.toString = function() {
return this.get_author() + ": " + this.get_title() + " (" +
this.get_isbn( ) + ")";
}
}
// класс, производный от класса Book
function DigitalBook(isbn, author, title, size) {
Book.call(this, isbn, author, title);
var _size = (size != null) ? size : 0;
this.get_size = function() {
return _size;
}
this.set_size = function(value) {
_size = value;
}
this.toString = function() {
return this.get_author() + ": " + this.get_title() + " (" +
this.get_isbn( ) + ")" +
" " + this.get_size() + " KB";
}
}
DigitalBook.prototype = new Book(); // Породить от book
var atlas = new DigitalBook("0123456789", "International Graphics",
"Atlas of the City");
atlas.set_size(1024);
document.write(atlas.toString());
</script>
</body>
</html>
Результат работы сценария приводится на рис. 2.5.
Доступ к элементам страницы 61
</body>
</html>
</body>
</html>
По умолчанию элемент <span> содержит три дефиса ( ). После щелчка
на кнопке дефисы будут замещены данными из текстового поля, в ко
торых служебные символы HTML будут замещены их эквивалентами.
Результат приводится на рис. 2.7.
Методы DOM
В большинстве ситуаций, когда необходимо организовать взаимодей
ствие с элементами HTMLстраницы, используется свойство innerHTML
элементов, доступ к которым организован с помощью специального
объекта JavaScript document.forms, родственных ему объектов или с по
мощью метода document.getElementById() (который возвращает элемент
по заданному идентификатору элемента). Однако иногда возникают
ситуации, когда требуется получить доступ к самой DOM. В списке ни
же приведены наиболее важные методы, предоставляющие такую воз
можность:
getElementsByTagName(name)
Возвращает массив всех элементов в странице с именем элемента name
createElement(name)
Создает новый узел DOM с именем элемента name
createAttribute(name)
Создает новый атрибут узла с именем атрибута name
createTextNode(text)
Создает новый текстовый узел DOM (текст внутри элемента) и запи
сывает в него текст text
66 Глава 2. JavaScript
appendChild(node)
Добавляет дочерний узел node к текущему элементу
Подведение итогов
В этой главе мы рассмотрели основы программирования на языке
JavaScript на стороне клиента. О дополнительных возможностях Java
Script будет рассказываться в следующих главах. Тем не менее в этой
главе вам были представлены все основные концепции, необходимые
для понимания остальной части книги.
Для дополнительного чтения 67
Объект XMLHttpRequest
Основу Ajax составляет объект XMLHttpRequest, который позволяет от
правлять HTTPзапросы и принимать ответы без необходимости от
правлять на сервер форму целиком и полностью обновлять страницу.
XMLHttpRequest и стандарты
Несмотря на то, что объект XMLHttpRequest поддерживается боль
шинством броузеров, он попрежнему не является стандартом,
так как не является частью спецификации ECMAScript. Однако
существует спецификация W3C, которая определяет похожую
функциональную особенность, а именно возможность динами
ческой загрузки и отправки на сервер данных в формате XML.
Эта спецификация называется «DOM Level 3 Load and Save»
и была рекомендована консорциумом W3C в апреле 2004 года
(http://www.w3.org/TR/DOMLevel3LS). Данный стандарт еще
не реализован ни в одном из наиболее популярных броузеров
и скорее всего пройдет какоето время, прежде чем разработчи
ки начнут работу над ним.
С другой стороны, недавно W3C выступил с инициативой стан
дартизации XMLHttpRequest. За дополнительной информацией об
ращайтесь по адресу: http://www.w3.org/TR/XMLHttpRequest.
window.alert(XMLHTTP.responseText);
}
}
</script>
</head>
<body>
<p>Wait and see ...</p>
</body>
</html>
Как видно на рис. 3.2, 3.3 и 3.4, этот пример прекрасно работает в In
ternet Explorer, Firefox и Konqueror (в последнем случае ASP.NET ра
ботает в среде Mono), то есть в наиболее распространенных броузерах.
Этот пример должен работать и в других броузерах при условии, что
в них будет включена поддержка JavaScript.
Объект XMLDocument
Свойство responseXML объекта XMLHttpRequest предполагает возвращение
результата обращения к удаленному серверу в виде объекта XMLDocu
ment. Для этого необходимо, чтобы программный код на стороне серве
ра возвращал данные в формате XML; в этом случае сценарий на сторо
не клиента сможет выполнить разбор этих данных. Получить доступ
к данным в формате XML несложно, т. к. вы обладаете полной под
держкой DOM.
JavaScript поддерживает всю необходимую функциональность DOM,
чтобы обращаться к конкретным узлам в файле XML или производить
обход древовидной структуры XMLдокумента. Полный перечень
свойств и методов объекта XMLDocument приводится в приложении B.
В следующем примере демонстрируется порядок использования неко
торых из них. В этом примере предполагается, что от сервера были по
лучены данные в формате XML, приведенные ниже:
<book title="Programming ASP.NET AJAX" author="Christian Wenz">
<chapters>
<chapter number="1" title="Introduction" />
<chapter number="2" title="JavaScript" />
<chapter number="3" title="Ajax" />
</chapters>
</book>
number=\"3\" title=\"Ajax\"
/></chapters></book>";
Response.ContentType = "text/xml";
Response.Write(xml);
Response.End();
}
}
Клиентский сценарий на JavaScript в этом примере извлекает из XML
документа и выводит такие данные, как атрибуты корневого узла и све
дения о различных главах объекта book.
Для вывода информации специально не использовался метод docu
ment.write(), потому что это привело бы к очистке содержимого теку
щей страницы, кроме того, такой способ болееменее работает в бро
узерах Mozilla, но, похоже, не поддерживается в Internet Explorer.
Вместо этого сценарий создает новые HTMLэлементы. Вообще суще
ствует два универсальных подхода: помещать данные в существующие
элементы или создавать новые.
Чтобы поместить данные в существующий элемент, следует записать
их в свойство innerHTML элемента. Рассмотрим HTMLдокумент, в кото
ром имеется следующий элемент <p>:
<p id="output">Wait and see ...</p>
Заменить содержимое этого элемента можно с помощью следующего
фрагмента на JavaScript:
document.getElementById("output").innerHTML = "Now you see!";
Альтернативный вариант заключается в создании новых элементов,
которые затем будут добавлены в страницу. Фрагмент ниже создает
пустой маркированный список:
<ul id="list"></ul>
Следующий фрагмент программного кода JavaScript добавит два эле
мента в этот список:
var list = document.getElementById("list");
var listItem1 = document.createElement("li");
var listItemText1 = document.createTextNode("Item 1");
listItem1.appendChild(listItemText1);
list.appendChild(listItem1);
var listItem2 = document.createElement("li");
var listItemText2 = document.createTextNode("Item 2");
listItem2.appendChild(listItemText2);
list.appendChild(listItem2);
Вернемся к задаче чтения данных из XMLдокумента. Фактически су
ществует два подхода к решению этой задачи. Первый, как показано
ниже, состоит в том, чтобы получать непосредственный доступ к тегам
по их именам, а затем извлекать значения их атрибутов.
Объект XMLDocument 83
function getXMLHTTP() {
var XMLHTTP = null;
if (window.ActiveXObject) {
try {
XMLHTTP = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
XMLHTTP = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
}
}
} else if (window.XMLHttpRequest) {
try {
XMLHTTP = new XMLHttpRequest( );
} catch (e) {
}
}
return XMLHTTP;
}
var XMLHTTP;
window.onload = function() {
XMLHTTP = getXMLHTTP();
if (XMLHTTP != null) {
XMLHTTP.open("GET", "xmldocument.aspx?sendData=ok");
XMLHTTP.onreadystatechange = stateChanged;
XMLHTTP.send(null);
}
}
function stateChanged() {
if (XMLHTTP.readyState == 4 &&
XMLHTTP.status == 200) {
var xml = XMLHTTP.responseXML;
var root = xml.documentElement;
document.getElementById("output").innerHTML =
root.getAttribute("title") +
" by " +
root.getAttribute("author");
var list = document.getElementById("list");
var chapters = xml.getElementsByTagName("chapter");
for (var i=0; i<chapters.length; i++) {
var listItem = document.createElement("li");
var listItemText = document.createTextNode(
chapters[i].getAttribute("number") +
": " +
chapters[i].getAttribute("title"));
listItem.appendChild(listItemText);
list.appendChild(listItem);
}
}
86 Глава 3. Ajax
}
</script>
</head>
<body>
<p id="output">Wait and see ...</p>
<ul id="list"></ul>
</body>
</html>
Результат работы этого сценария приводится на рис. 3.6.
JSON
Третья основная технология, помимо XMLHttpRequest и XML, часто
используемая в Ajaxприложениях, – это JavaScript Object Notation
(JSON – представление объектов JavaScript, http://www.json.org/). Ис
пользование формата JSON позволяет хранить (сериализовать, или пе
реводить в последовательную форму) объекты JavaScript или данные
в компактном и понятном виде, при этом не требуя большого объема
программного кода JavaScript для чтения и записи данных (выполняет
ся и для XML). Формат JSON основан на использовании часто упускав
шейся из виду особенности JavaScript, или, если быть более точным,
спецификации языка ECMAScript, известной также как ECMA262.
Формат JSON используется внутренними механизмами текущей вер
сии ASP.NET AJAX и в общем случае может использоваться для обме
на с сервером данными, имеющими сложную структуру. Он является
«родным» для JavaScript и позволяет избежать порой достаточно гро
моздкого процесса разбора формата XML. Следующий фрагмент опре
деляет объект book в формате JSON:
{"book": {
"title": "Programming ASP.NET AJAX",
JSON 87
</script>
</body>
</html>
Результат работы этого сценария приводится на рис. 3.7.
Как видно из рис. 3.7, данные в формате JSON – названия трех глав –
были выведены броузером. Фигурные скобки, которые можно видеть
в примере 3.3, используются для определения свойств объектов, а квад
ратные скобки – для определения массивов.
Кроме того, вы должны обратить внимание на фрагмент, который с точ
ки зрения безопасности выглядит весьма сомнительно. Следующая
строка производит интерпретацию кода JSON во время исполнения:
eval("var obj = " + json + ";");
В этой строке используется встроенная функция JavaScript – eval(), ко
торая производит интерпретацию программного кода во время исполне
ния. Некоторые программисты считают использование этой функции
дурным тоном, но здесь кроется еще большая опасность, которая заклю
чается в том, что функция eval() слепо доверяет программному коду,
который она интерпретирует. В примере выше данные в формате JSON
являются составной частью сценария, поэтому им можно доверять.
В Ajaxприложениях данные обычно поступают с того же сервера, отку
да была получена сама страница. Безоговорочное доверие к данным, ко
торое проявляет функция eval(), может оказаться опасным, особенно
если страница, откуда поступают объекты JSON, неподконтрольна вам
или имеет место злонамеренный сбой настроек компьютера, на котором
выполняется сценарий (то есть действует шпионская программа, кото
рая перенаправляет запросы с одного сервера на другой). Поэтому будь
те осторожны в обращении с функцией eval() и используйте ее для ин
терпретации только тех данных, которым вы полностью доверяете.
Подведение итогов 89
Использование (и предотвращение)
кэширования на стороне клиента
Броузеры часто используют механизм кэширования, поскольку
он позволяет им ускорять загрузку страниц. Вебмастера ничего
не имеют против механизма кэширования, так как он помогает
снизить нагрузку на сервер. Однако иногда для разработчиков
механизм кэширования становится нежелательным. Например,
если броузер берет устаревшую версию страницы из кэша, это
может существенно усложнить процесс отладки. В мире Ajax это
очень распространенная проблема. Однако имеется два простых
решения. Первое решение заключается в том, чтобы добавить
в URL ложный параметр GETзапроса для объекта XMLHttpRequest,
который не оказывает никакого влияния на конечный результат,
но позволяет избежать кэширования данных, потому что строка
URL изменяется от запроса к запросу. Следующий фрагмент де
монстрирует, как это можно реализовать на практике.
XMLHTTP.open("GET", "xmldocument.aspx?sendData=ok&token="
+ Math.random( ));
Этот фрагмент будет добавлять в URL нечто подобное &token=0.
19964476288175226, придавая ему уникальность. Второе решение
заключается в установке в HTTPзапросе дополнительного заго
ловка If Modified Since, обращенного к моменту времени в про
шлом. Это заставит броузер всякий раз запрашивать новую вер
сию данных; запрос приведен ниже:
XML.setRequestHeader(
"If Modified Since",
"Tuesday, 1 Jan 1980 12:00:00 GMT");
Любой из этих приемов может использоваться для облегчения
отладки на этапе разработки. Однако на этапе эксплуатации
встроенный в броузеры механизм кэширования может способст
вовать повышению производительности вашего приложения (ес
ли это не приводит к появлению нежелательных побочных эф
фектов), а кэширование на стороне сервера может дать еще боль
ший эффект. Результат всегда зависит от конкретного сценария,
для которого применяется механизм кэширования.
Подведение итогов
В этой главе были рассмотрены три технологии, составляющие основу
Ajax, из которых наиболее важным является объект XMLHttpRequest.
Кроме того, вы увидели, как структурированные данные, получаемые
90 Глава 3. Ajax
Псевдонимы и вспомогательные
функции ASP.NET AJAX
Включая в вебстраницу ScriptManager – элемент управления ASP.NET
AJAX, вы автоматически получаете ряд удобных вспомогательных
функций и псевдонимов для доступа к важным особенностям Java
Script. Некоторые из этих функций просто позволяют сократить вре
мя, затрачиваемое на ввод с клавиатуры. Но другие дают гораздо более
существенное преимущество: независимость от типа броузера. Напри
мер, Internet Explorer с одной стороны и все современные броузеры –
с другой, обеспечивают свой собственный способ организации подпис
ки на обработку событий (глава 2). Платформа ASP.NET AJAX опре
деляет тип броузера и автоматически использует функцию, соответст
вующую той или иной системе.
Псевдонимы
При создании современных вебсайтов, использующих JavaScript, раз
работчики очень часто используют метод document.getElementById(). Не
94 Глава 4. Использование расширений JavaScript в ASP.NET AJAX
Расширения к существующим
объектам JavaScript
В главе 2 упоминалось о добавлении методов к базовым объектам Java
Script. Разработчики ASP.NET AJAX очень широко пользуются этой
возможностью. В результате дополнительными характеристиками бы
ли дополнены следующие базовые типы JavaScript:
Объектно"ориентированные возможности JavaScript в ASP.NET AJAX 97
• Array
• Boolean
• Date
• Error
• Number
• Object
• String
Каждое из этих дополнений по отдельности не является чемто особен
ным, но все вместе они могут дать существенный выигрыш при написа
нии больших объемов программного кода JavaScript. Не забывайте, что
основная идея любой рабочей среды Ajax состоит в том, чтобы миними
зировать объем программного кода, который придется писать вручную.
Вместо полного списка новых методов я представлю лишь простой
пример. Представим, что нам нужен новый метод Array.forEach(), ко
торый будет применять некоторую функцию к каждому элементу за
данного массива.
function Array$forEach(a, fnct) {
for (var i = 0; i = a.length; i++) {
if (typeof(a[i]) != "undefined") {
fnct.call(null, a[i], i, a);
}
}
}
Оказывается, что имеется встроенный в ASP.NET AJAX метод
forEach(), позволяющий сэкономить время, которое пришлось бы за
тратить на ввод с клавиатуры, отладку и сопровождение.
Объектноориентированные
возможности JavaScript в ASP.NET AJAX
В главе 2 мы узнали, что в JavaScript имеются некоторые особенности,
характерные для объектноориентированного программирования, но
они не вполне соответствуют возможностям ООП, которые имеются
в других языках программирования, таких как Visual Basic или C#.
Пространства имен
Ключевой особенностью объектноориентированных расширений Java
Script в ASP.NET AJAX является добавление функциональности про
странств имен (namespaces). Они позволяют объединять функции в ло
гические группы под общим именем. Помогают избежать конфликтов
имен, когда имеется несколько функций с одинаковыми именами, но
преследующих различные цели. Спецификация языка JavaScript не
предусматривает наличие пространств имен, поэтому данная возмож
ность отсутствует в самом языке. Однако платформа ASP.NET AJAX
способна эмулировать пространства имен, используя для этого доволь
но простой прием. Этот прием заключается в следующем: сначала соз
дается новый класс (который выступает в роли «пространства имен»),
а затем создается другой (новый) класс, как свойство класса простран
ства имен. Это позволяет обращаться к классу с использованием нота
ции ИмяКлассаПространстваИмен.ИмяВашегоКласса.
Одним из базовых классов платформы ASP.NET AJAX является класс
Type. Этот класс имеет два удобных метода, которые позволяют созда
вать пространства имен в ASP.NET AJAX:
Type.registerNamespace(name)
Регистрирует пространство имен
Type.registerClass(name, base type, interface type)
Регистрирует класс как член пространства имен
Для демонстрации использования этой техники мы создадим про
странство имен OReilly, которое будет объединять в себе несколько
классов, используемых в этой книге. Допустим, что один из этих клас
сов называется Software и имеет два свойства: name и vendor. Для начала
необходимо зарегистрировать пространство имен OReilly:
Type.registerNamespace("OReilly");
Затем с помощью следующего фрагмента создадим класс Software, как
элемент пространства имен OReilly:
Объектно"ориентированные возможности JavaScript в ASP.NET AJAX 99
this.getVendor = function() {
return _vendor;
}
this.setVendor = function(vendor) {
_vendor = vendor;
}
}
Type.registerClass("OReilly.Software");
var ie = new OReilly.Software("Internet Explorer", "Microsoft");
s = ie.getName() + " from " + ie.getVendor() + "<br />";
var ff = new OReilly.Software();
ff.setName("Firefox");
ff.setVendor("Mozilla Foundation");
s += ff.getName() + " from " + ff.getVendor();
document.getElementById("output").innerHTML = s;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div id="output">
</div>
</form>
</body>
</html>
На рис. 4.1 приводится результат работы сценария после полной за
грузки страницы.
Наследование классов
Как отмечалось в главе 2, ограниченная поддержка механизма насле
дования классов в JavaScript обеспечивается с помощью свойства pro
totype. Платформа ASP.NET AJAX обеспечивает дополнительный уро
вень абстракции. Механизм prototype поддерживается и для классов
пространств имен, которые регистрируются с помощью метода Class
Name.registerClass(). Во втором аргументе этого метода можно указать
базовый класс. То есть можно задать, от какого класса порожден теку
щий класс.
Производные классы
Давайте попробуем создать класс, производный от класса Software.
Броузеры являются одной из разновидностей программного обеспече
ния, поэтому создадим класс Browser. В дополнение к свойствам поро
ждающего класса Software, броузеры должны обладать некоторыми до
полнительными свойствами. Свойство isJavaScriptSupported может да
вать информацию о том, поддерживает ли данный броузер возмож
ность исполнять сценарии на языке JavaScript.
OReilly.Browser = function(name, vendor, isJavaScriptSupported) {
//...
}
Ниже демонстрируется порядок регистрации класса. Обратите внима
ние на то, как новый класс (строковый параметр) наследует класс
OReilly.Software (это уже не строка!).
OReilly.Browser.registerClass("OReilly.Browser", OReilly.Software);
Разумеется, можно было бы снова создать методы для доступа к свойст
вам name и vendor и написать программный код конструктора. Но одно
из преимуществ наследования (фактически, главное преимущество) со
стоит в том, что существует возможность повторного использования
функциональности базового класса. Поскольку OReilly.Browser являет
ся наследником OReilly.Software, можно использовать уже имеющиеся
методы получения и задания значений (то есть сами свойства), а также
«частные» члены _name и _vendor. Нам только потребуется добавить ме
тоды доступа и частные члены для нового свойства isJavaScriptSup
ported, как показано ниже:
var _isJavaScriptSupported = (isJavaScriptSupported != null) ?
isJavaScriptSupported : false;
this.getIsJavaScriptSupported = function() {
return _isJavaScriptSupported;
Объектно"ориентированные возможности JavaScript в ASP.NET AJAX 103
}
this.setIsJavaScriptSupported = function(isJavaScriptSupported) {
_isJavaScriptSupported = isJavaScriptSupported;
}
Теперь все, что осталось сделать, – это написать конструктор. Но вме
сто того, чтобы снова писать его с самого начала, можно воспользо
ваться конструктором базового класса. Для этой цели ASP.NET AJAX
предоставляет метод initializeBase(). В первом параметре этому мето
ду передается экземпляр класса, для которого должен быть вызван
конструктор базового класса – как правило, используется значение
this. Второй параметр – это массив аргументов для передачи конст
руктору базового класса (набор аргументов определяется базовым
конструктором). В нашем случае этот массив будет содержать назва
ние броузера и производителя.
OReilly.Browser.initializeBase(this, new Array(name, vendor));
return _vendor;
}
this.setVendor = function(vendor) {
_vendor = vendor;
}
}
Type.registerClass("OReilly.Software");
OReilly.Browser = function(name, vendor, isJavaScriptSupported) {
OReilly.Browser.initializeBase(this, new Array(name, vendor));
var _isJavaScriptSupported = (isJavaScriptSupported != null) ?
isJavaScriptSupported : false;
this.getIsJavaScriptSupported = function() {
return _isJavaScriptSupported;
}
this.setIsJavaScriptSupported = function(isJavaScriptSupported) {
_isJavaScriptSupported = isJavaScriptSupported;
}
}
OReilly.Browser.registerClass("OReilly.Browser", OReilly.Software);
var ie = new OReilly.Browser("Internet Explorer", "Microsoft", true);
s = ie.getName() + " from " + ie.getVendor() +
(ie.getIsJavaScriptSupported() ? " (w/ JS)" : " (w/o JS)") +
"<br />";
var lynx = new OReilly.Browser("Lynx");
lynx.setIsJavaScriptSupported(false);
s += lynx.getName() + " from " + lynx.getVendor() +
(lynx.getIsJavaScriptSupported() ? " (w/ JS)" : " (w/o JS)");
document.getElementById("output").innerHTML = s;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div id="output">
</div>
</form>
</body>
</html>
На рис. 4.2 приводится результат работы сценария после загрузки
страницы.
}
this.setName = function(name) {
_name = name;
}
this.getVendor = function() {
return _vendor;
}
this.setVendor = function(vendor) {
_vendor = vendor;
}
}
Type.registerClass("OReilly.Software");
OReilly.Browser = function(name, vendor, isJavaScriptSupported) {
OReilly.Browser.initializeBase(this, new Array(name, vendor));
var _isJavaScriptSupported = (isJavaScriptSupported != null) ?
isJavaScriptSupported : false;
this.getIsJavaScriptSupported = function() {
return _isJavaScriptSupported;
}
this.setIsJavaScriptSupported = function(isJavaScriptSupported) {
_isJavaScriptSupported = isJavaScriptSupported;
}
}
OReilly.Browser.registerClass("OReilly.Browser", OReilly.Software);
OReilly.Software.prototype.toString = function() {
return this.getName() + " from " + this.getVendor();
}
OReilly.Browser.prototype.toString = function() {
return OReilly.Browser.callBaseMethod(this, "toString") +
(this.getIsJavaScriptSupported() ? " (w/ JS)" : " (w/o JS)");
};
var ie = new OReilly.Browser("Internet Explorer", "Microsoft", true);
s = ie.toString() + "<br />";
var lynx = new OReilly.Browser("Lynx", null, false);
s += lynx.toString();
document.getElementById("output").innerHTML = s;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div id="output">
</div>
</form>
108 Глава 4. Использование расширений JavaScript в ASP.NET AJAX
</body>
</html>
Примечательно, что результат работы этого сценария совпадает с тем,
что был продемонстрирован на рис. 4.2.
Интерфейсы
Последняя объектноориентированная особенность, появившаяся в Ja
vaScript благодаря ASP.NET AJAX, – это интерфейсы. Они вообще не
содержат в себе реализации чего бы то ни было, а просто определяют
набор членов, которые должны быть реализованы в классахнаследни
ках. При наследовании интерфейсов вы не получаете никакой реали
зации для использования. Напротив, вы должны создать методы, объ
явленные в интерфейсе. Это прекрасный способ разделения структуры
класса и его реализации.
Как вы уже, вероятно, догадались, интерфейсы создаются вызовом ме
тода Type.registerInterface(). Имя вновь созданного интерфейса затем
может быть передано методу registerClass() в третьем (необязатель
ном) аргументе. Таким образом, если начинать реализацию приложе
ния с интерфейса, мы могли бы начать со следующего фрагмента:
OReilly.IProduct = function() {
this.toString = Function.abstractMethod;
}
Type.registerInterface("OReilly.IProduct");
Ниже приводится определение абстрактного класса OReilly.Product.
К сожалению, окончательная версия ASP.NET AJAX не поддержива
ет абстрактные классы (в предварительной версии такая поддержка
существовала). Таким образом, можно считать, что чисто технически
между обычными и абстрактными классами нет никакой разницы.
В следующем примере класс OReilly.Product объявляет и реализует
свойства name и vendor.
OReilly.Product = function(name, vendor) {
var _name = (name != null) ? name : "unknown";
var _vendor = (vendor != null) ? vendor : "unknown";
this.getName = function() {
return _name;
}
this.setName = function(name) {
_name = name;
}
this.getVendor = function() {
return _vendor;
}
this.setVendor = function(vendor) {
Объектно"ориентированные возможности JavaScript в ASP.NET AJAX 109
_vendor = vendor;
}
}
Type.registerClass("OReilly.Product");
Следующий на очереди класс – OReilly.Software. Поскольку мы не
предполагаем создавать экземпляры этого класса (для этих целей мы
будем использовать классы, подобные OReilly.Browser), то он будет вы
полнять роль абстрактного класса. Он наследует свойства класса
OReilly.Product (name и vendor), а также реализует интерфейс OReilly.IPro
duct (метод toString()). После объявления класса мы зарегистрируем
его следующим вызовом метода Type.registerClass():
OReilly.Software.registerClass("OReilly.Software", OReilly.Product,
OReilly.IProduct);
Остальная часть программного кода останется без изменений. Сцена
рий получился достаточно длинным, поэтому, чтобы не загромождать
файл .aspx, имеет смысл поместить его в отдельный файл с расширени
ем .js. Полный исходный текст приводится в примере 4.4.
Пример 4.4. Использование интерфейса для структурирования
программного кода
ClientInterface.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<script language="Javascript" type="text/javascript">
function pageLoad() {
var s = "";
Type.registerNamespace("OReilly");
OReilly.IProduct = function() {
this.toString = Function.abstractMethod;
}
Type.registerInterface("OReilly.IProduct");
OReilly.Product = function(name, vendor) {
var _name = (name != null) ? name : "unknown";
var _vendor = (vendor != null) ? vendor : "unknown";
this.getName = function() {
return _name;
}
this.setName = function(name) {
_name = name;
}
110 Глава 4. Использование расширений JavaScript в ASP.NET AJAX
this.getVendor = function() {
return _vendor;
}
this.setVendor = function(vendor) {
_vendor = vendor;
}
}
Type.registerClass("OReilly.Product");
OReilly.Software = function(name, vendor) {
var _name = (name != null) ? name : "unknown";
var _vendor = (vendor != null) ? vendor : "unknown";
this.getName = function() {
return _name;
}
this.setName = function(name) {
_name = name;
}
this.getVendor = function() {
return _vendor;
}
this.setVendor = function(vendor) {
_vendor = vendor;
}
}
OReilly.Software.registerClass("OReilly.Software", OReilly.Product,
OReilly.IProduct);
OReilly.Software.prototype.toString = function() {
return this.getName() + " from " + this.getVendor();
}
OReilly.Browser = function(name, vendor, isJavaScriptSupported) {
OReilly.Browser.initializeBase(this, new Array(name, vendor));
var _isJavaScriptSupported =
(isJavaScriptSupported != null) ? vendor : false;
this.getIsJavaScriptSupported = function() {
return _isJavaScriptSupported;
}
this.setIsJavaScriptSupported = function(isJavaScriptSupported) {
_isJavaScriptSupported = isJavaScriptSupported;
}
}
OReilly.Browser.registerClass("OReilly.Browser", OReilly.Software);
OReilly.Browser.prototype.toString = function() {
return OReilly.Browser.callBaseMethod(this, "toString") +
(this.getIsJavaScriptSupported() ? " (w/ JS)" : " (w/o JS)");
}
var ie = new OReilly.Browser("Internet Explorer", "Microsoft", true);
Клиентские версии классов .NET 111
Sys.StringBuilder
Одной из новых возможностей, появившихся в .NET 1.0, которая дей
ствительно позволяет поднять производительность, стал класс String
Builder. Приложения, как правило, включают в себя массу фрагмен
тов кода, напоминающих тот, что приводится ниже:
string s = "", t;
while () {
t = <value>;
s += t;
}
112 Глава 4. Использование расширений JavaScript в ASP.NET AJAX
<div id="output"></div>
</form>
</body>
</html>
Встроенная в JavaScript функция String.fromCharCode() преобразует
код ASCII в соответствующий ему символ, таким образом, вложенный
цикл for выполняет перебор символов от «a» до «h». Как показано на
рис. 4.3, сценарий из примера 4.5 воссоздает простейшее представле
ние шахматной доски.
Перечисления
Еще один тип, который эмулируется платформой ASP.NET AJAX
в JavaScript, – это Enum. Он позволяет создавать собственные перечис
ления с помощью метода createEnum(). В процессе перехода от Atlas
к ASP.NET AJAX прикладной интерфейс данной особенности изме
нился весьма незначительно. В текущем виде класс Enum позволяет
программисту создавать свои собственные перечисления, как показа
но в следующем листинге, но не предусматривает возможности выпол
нять обход значений в цикле. При желании для хранения перечисле
ний можно создать свое пространство имен:
Type.registerNamespace("ORA.MyEnums");
Затем можно создать свое перечисление, присвоив ему пустую функ
цию:
ORA.MyEnums.Ajax = function( ) {};
После этого выполняется объявление значений в перечислении, как
показано ниже:
114 Глава 4. Использование расширений JavaScript в ASP.NET AJAX
ORA.MyEnums.Ajax.prototype = {
"Asynchronous": 0,
"JavaScript": 1,
"and": 2,
"XML": 3
};
И в заключение перечисление необходимо зарегистрировать:
ORA.MyEnums.Ajax.registerEnum("ORA.MyEnums.Ajax");
В примере 4.6 демонстрируется порядок создания перечисления и его
использования.
Пример 4.6. Использование класса Enum платформы ASP.NET AJAX
ClientEnum.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<script language="Javascript" type="text/javascript">
function pageLoad() {
Type.registerNamespace("ORA.MyEnums");
ORA.MyEnums.Ajax = function() {};
ORA.MyEnums.Ajax.prototype = {
"Asynchronous": 0,
"JavaScript": 1,
"and": 2,
"XML": 3
};
ORA.MyEnums.Ajax.registerEnum("ORA.MyEnums.Ajax");
document.getElementById("output").innerHTML +=
ORA.MyEnums.Ajax.Asynchronous + " " +
ORA.MyEnums.Ajax.JavaScript + " " +
ORA.MyEnums.Ajax.and + " " +
ORA.MyEnums.Ajax.XML;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div id="output"></div>
</form>
</body>
</html>
Подведение итогов 115
Этот пример выводит внутри элемента <div> строку "0 1 2 3" (ключи эле
ментов перечисления).
Аналогичным образом перечисления используются платформой
ASP.NET AJAX для определения кнопок мыши (как показано в сле
дующем фрагменте, который был подредактирован и отформатирован
для лучшего восприятия).
Sys.UI.MouseButton = function( ) { };
Sys.UI.MouseButton.prototype = {
leftButton:0,
middleButton:1,
rightButton:2
};
Sys.UI.MouseButton.registerEnum("Sys.UI.MouseButton");
Подведение итогов
Библиотека клиентских сценариев платформы ASP.NET AJAX реали
зует несколько удобных особенностей, отсутствующих в стандартном
JavaScript, включая объектноориентированные возможности и экви
валенты функциональных возможностей .NET Framework на стороне
клиента. Эти особенности могут использоваться любым программи
стом на JavaScript, без оглядки на ASP.NET или серверные функции
ASP.NET AJAX.
Обработка ошибок
До сих пор, работая с вебслужбой, мы предполагали, что программ
ный код, обрабатывающий наши запросы на стороне сервера, всегда
работает безошибочно. Однако в действительности при обработке за
просов могут возникать исключительные ситуации, которые мы еще
не рассматривали.
При работе с вебслужбами, исполняемыми на удаленных серверах
(в дальнейшем обсуждении мы будем подразумевать серверы из других
доменов), разработчики очень часто не включают программный код об
работки ошибок. Одна из причин состоит в том, что вебслужба может
быть реализована на основе любой технологии, и каждая из технологий
предполагает свой собственный способ обработки исключений. Некото
рые реализации вообще не возбуждают исключительные ситуации.
Однако в случае ASP.NET AJAX и Ajax порядок взаимодействия с веб
службами несколько иной. Непосредственное обращение к удаленной
Обработка ошибок 117
get_exceptionType()
Возвращает тип исключения
get_message()
Возвращает сообщение об ошибке, сопровождающей исключение
get_stackTrace()
Возвращает трассировочную информацию об ошибке
get_statusCode()
Возвращает код состояния, отправленный сервером
get_timeOut()
Возвращает признак превышения предельного времени ожидания
Данная информация выводится в элемент <div>, который был создан
специально для этих целей:
function callError(result) {
document.getElementById("output").innerHTML =
"<b>" +
result.get_exceptionType() +
"</b>: " +
result.get_message() +
"<br />" +
result.get_stackTrace();
}
Остальная часть примера не содержит ничего сложного. В случае нор
мального завершения вебслужбы результат деления будет выводить
ся в элемент <span>. Полный текст примера находится в примере 5.2.
Об отображении (и сокрытии)
сообщений об ошибках
Возможность отображения сообщений об ошибках на стороне
клиента представляет собой прекрасное подспорье при отладке
приложений, но в окончательной версии она может нести опре
деленную угрозу. Сообщения об ошибках могут содержать ин
формацию секретного характера, например строку подключе
ния. Даже если вы не предусматриваете вывод такой информа
ции, ASP.NET AJAX может сам отправлять ее клиенту каким
либо способом. Уменьшить потенциальную угрозу можно двумя
способами. Первый заключается в том, чтобы отказаться от вы
вода на стороне клиента подробных сведений об ошибке, таких
как трассировочная информация. Второй способ: при возбужде
нии исключений на стороне сервера старайтесь встраивать в них
как можно меньше информации.
120 Глава 5. Веб"службы
<br />
<input type="button" value="Divide Numbers"
onclick="callService(this.form);" />
<br />
<div id="output" style="width: 600px; height: 300px;">
</div>
</div>
</form>
</body>
</html>
Теперь, выполнив деление числа 6 на 7, вы получите, как и следовало
ожидать, число 0.8571429. Однако если попытаться разделить число 6
на 0, вебслужба выставляет вполне предсказуемое исключение. Ре
зультат такой попытки, включая некоторую трассировочную инфор
мацию, приводится на рис. 5.1.
Методы страницы
Вероятно, вы уже заметили, что размещение всех вебметодов прило
жения в отдельном файле – занятие несколько утомительное. С архи
тектурной точки зрения такой способ размещения программного кода
выглядит неплохо. Но в случае простых сценариев или приложений
(как большинство примеров в этой книге) дополнительные файлы
.asmx приводят только к загромождению проекта.
Добавив лишь немного дополнительного кода, вы сможете разместить
все необходимое в одном месте, а именно – в главном файле .aspx (или
в файле с реализацией класса). Для этого необходимо выполнить два
условия. Первое: с помощью директивы @ Import импортировать про
странство имен вебслужбы в файл страницы, как показано ниже:
<%@ Import Namespace="System.Web.Services" %>
122 Глава 5. Веб"службы
result.get_message() +
"<br />" +
result.get_stackTrace();
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"
EnablePageMethods="true">
</asp:ScriptManager>
<div>
<nobr>
<input type="text" id="a" name="a" size="2" />
/
<input type="text" id="b" name="b" size="2" />
= <span id="c" style="width: 50px;"></span>
</nobr>
<br />
<input type="button" value="Divide Numbers"
onclick="callService(this.form);" />
<br />
<div id="output" style="width: 600px; height: 300px;">
</div>
</div>
</form>
</body>
</html>
На рис. 5.2 показан результат, который будет отображен после того,
как выполнена загрузка страницы, введены два числа и выполнен
щелчок на кнопке Divide Numbers.
return diff.TotalSeconds;
}
}
Теперь вернемся к приложению, которое выполняет деление двух чи
сел. Когда будет загружена страница, содержащая фрагмент, приведен
ный выше, и произойдет вызов метода SaveTime(), внутри сеанса будет
сохранено текущее время. Во время выполнения операции деления бу
дет вычислена разность между двумя значениями времени. Это даст
возможность определить, какой промежуток времени прошел между от
крытием формы и запросом на выполнение операции деления (конечно,
то же самое можно было бы сделать обычными средствами JavaScript,
но для демонстрации мы используем обходной путь через сервер).
Следующий фрагмент программного кода на JavaScript сразу после за
грузки страницы сохраняет текущее время вызовом метода SaveTime()
вебслужбы. Поскольку возвращаемое значение этого метода не пред
ставляет никакого интереса, мы можем использовать функцию обрат
ного вызова, которая ничего не делает.
function pageLoad(){
PageMethods.SaveTime(doNothing, doNothing);
}
function doNothing(result) {
// ничего не делает : )
}
Как уже было показано ранее, чтобы вызвать метод CalculateDiffer
ence() вебслужбы, необходимо обратиться к методу callService().
В следующем фрагменте производится вызов двух методов вебслуж
бы. Первый вычисляет разницу между временем загрузки страницы
и текущим временем. Второй выполняет ту же арифметическую опе
рацию, что и раньше.
function callService(f) {
document.getElementById("c").innerHTML = "";
PageMethods.CalculateDifference(
showDifference,
callError);
PageMethods.DivideNumbers(
parseInt(f.elements["a"].value),
parseInt(f.elements["b"].value),
callComplete,
callError);
}
Наконец, необходимо предусмотреть код разметки для отображения
разности времен. Для этих целей мы будем использовать контейнер
<div> со значением атрибута "id=output". Обратите внимание: когда веб
метод возвращает значение 1, это означает, что текущее время не было
сохранено в сеансе и потому разность времен не может быть вычислена.
Управление состоянием сеанса 127
function showDifference(result) {
if (result != 1) {
document.getElementById("output").innerHTML =
"The form has been open for " + result + " seconds";
}
}
Полный код разметки и текст сценария, которые необходимо реализо
вать, приводятся в примере 5.4, а все сделанные изменения выделены
жирным шрифтом. Обратите внимание: для элемента управления
ScriptManager, как и прежде, необходимо установить атрибут EnablePa
geMethods="true". Если этот атрибут не установлен, методы страницы не
будут работать.
Пример 5.4. Управление состоянием сеанса средствами ASP.NET AJAX
и ASP.NET
WebServiceSession.aspx
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Web.Services" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<script runat="server">
[WebMethod(EnableSession = true)]
[System.Web.Script.Services.ScriptMethod]
public static bool SaveTime()
{
HttpContext.Current.Session["PageLoaded"] = DateTime.Now;
return true;
}
[WebMethod(EnableSession = true)]
[System.Web.Script.Services.ScriptMethod]
public static double CalculateDifference()
{
if (HttpContext.Current.Session["PageLoaded"] == null) {
return 1;
} else {
DateTime then = (DateTime)HttpContext.Current.Session["PageLoaded"];
TimeSpan diff = DateTime.Now.Subtract(then);
return diff.TotalSeconds;
}
}
[WebMethod]
[System.Web.Script.Services.ScriptMethod]
public static float DivideNumbers(int a, int b)
{
if (b == 0)
{
throw new DivideByZeroException();
128 Глава 5. Веб"службы
}
else
{
return (float)a / b;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
<script language="Javascript" type="text/javascript">
function pageLoad() {
PageMethods.SaveTime(doNothing, doNothing);
}
function doNothing(result) {
// ничего не делает : )
}
function callService(f) {
document.getElementById("c").innerHTML = "";
PageMethods.CalculateDifference(
showDifference,
callError);
PageMethods.DivideNumbers(
parseInt(f.elements["a"].value),
parseInt(f.elements["b"].value),
callComplete,
callError);
}
function showDifference(result) {
if (result != 1) {
document.getElementById("output").innerHTML =
"The form has been open for " + result + " seconds";
}
}
function callComplete(result) {
document.getElementById("c").innerHTML = result;
}
function callError(result) {
if (result == null) {
window.alert("Error!");
} else {
document.getElementById("output").innerHTML =
"<b>" +
result.get_exceptionType() +
"</b>: " +
result.get_message() +
"<br />" +
result.get_stackTrace();
Управление состоянием сеанса 129
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"
EnablePageMethods="true">
</asp:ScriptManager>
<div>
<nobr>
<input type="text" id="a" name="a" size="2" />
/
<input type="text" id="b" name="b" size="2" />
= <span id="c" style="width: 50px;"></span>
</nobr>
<br />
<input type="button" value="Divide Numbers"
onclick="callService(this.form);" />
<br />
<div id="output" style="width: 600px; height: 300px;">
</div>
</div>
</form>
</body>
</html>
При вызове из броузера метода DivideNumbers() можно заметить два от
личия от предыдущих примеров. Первое: вебсервер отправляет сеан
совый cookie (если в файле Web.config вы не задали использование се
ансов без cookie). Если броузер настроен на запрос подтверждения пе
ред приемом cookie, вы увидите диалог, как показано на рис. 5.3. Вто
рое: при обращении к вебслужбе производится сохранение данных
сеанса (рис. 5.4).
}
[WebMethod]
public DivisionData ExtendedDivideNumbers(int a, int b)
{
if (b == 0)
{
throw new DivideByZeroException();
}
else
{
float res = (float)a / b;
string stamp = DateTime.Now.ToLongTimeString();
DivisionData d = new DivisionData();
d.result = res;
d.calculationTime = stamp;
return d;
}
}
}
Обратное преобразование объекта DivisionData (десериализация) на
стороне клиента выполняется автоматически. Результаты обращения
к вебслужбе содержатся в свойствах result и calculationTime объекта
DivisionData. Дополненный программный код JavaScript, который вы
полняет обращение к вебслужбе, демонстрируется в примере 5.6.
Пример 5.6. Страница, принимающая от вебслужбы данные
со сложной структурой
Complex.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
<script language="Javascript" type="text/javascript">
function callService(f) {
document.getElementById("c").innerHTML = "";
document.getElementById("output").innerHTML = "";
MathService.ExtendedDivideNumbers(
parseInt(f.elements["a"].value),
parseInt(f.elements["b"].value),
callComplete,
callError);
}
function callComplete(result) {
document.getElementById("c").innerHTML =
Обмен данными со сложной структурой 133
result.result +
" (calculated at " +
result.calculationTime +
")";
}
function callError(result) {
document.getElementById("output").innerHTML =
"<b>" +
result.get_exceptionType() +
"</b>: " +
result.get_message() +
"<br />" +
result.get_stackTrace();
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="MathService.asmx" />
</Services>
</asp:ScriptManager>
<div>
<nobr>
<input type="text" id="a" name="a" size="2" />
/
<input type="text" id="b" name="b" size="2" />
=
<span id="c" style="width: 50px;"></span>
</nobr>
<br />
<input type="button" value="Divide Numbers"
onclick="callService(this.form);" />
<br />
<div id="output" style="width: 600px; height: 300px;">
</div>
</div>
</form>
</body>
</html>
Результат работы сценария, который выводит сразу оба значения – ре
зультат деления и время, приводится на рис. 5.5.
Если перехватить трафик HTTP, который генерируется этим сценари
ем, можно увидеть, как выглядят эти данные в формате JSON (рис. 5.6).
К настоящему моменту вы узнали о специфических особенностях веб
служб, предлагаемых платформой ASP.NET AJAX, которые весьма
сложно было бы реализовать исключительно средствами JavaScript.
134 Глава 5. Веб"службы
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ASP.NET AJAX</title>
<script language="Javascript" type="text/javascript">
function callService(f) {
document.getElementById("c").innerHTML = "";
WebService.useService("MathService.asmx?WSDL", "MathService");
WebService.MathService.callService(
callComplete,
"DivideNumbers",
f.elements["a"].value, f.elements["b"].value);
}
function callComplete(result) {
document.getElementById("c").innerHTML = result.value;
}
</script>
</head>
<body>
<div id="WebService" style="behavior:url(webservice.htc);">
</div>
<form method="post" onsubmit="return false;">
<div>
<nobr>
<input type="text" id="a" name="a" size="2" />
:
<input type="text" id="b" name="b" size="2" />
=
<span id="c" style="width: 50px;"></span>
</nobr>
<br />
<input type="button" value="Divide Numbers"
onclick="callService(this.form);" />
</div>
</form>
</body>
</html>
p1.schemaType = stype;
p2.schemaType = stype;
Затем необходимо собрать запрос к вебслужбе. Делается это с помо
щью метода encode(), но только после подготовки всех входных пара
метров, как показано в следующем фрагменте:
soapcall.encode(
0, // значение по умолчанию для SOAP 1.1
"DivideNumbers", // имя веб метода
"http://hauser wenz.de/AspNetAJAX/", // Пространство имен
0, // количество дополнительных заголовков
new Array(), // дополнительные заголовки
2, // количество параметров
new Array(p1, p2) // параметры
);
Наконец, нужно выполнить асинхронный вызов вебслужбы с помо
щью метода asyncInvoke(). В качестве параметра этому методу переда
ется ссылка на функцию обратного вызова.
soapcall.asyncInvoke(callComplete);
Функция обратного вызова принимает три параметра:
• Результат работы вебслужбы в формате XML
• Объект SOAPCall (на тот случай, если вас заинтересует содержимое
SOAPзаголовков)
• Код HTTPстатуса вызова
Единственное, что осталось сделать, – это извлечь информацию из по
лученного XMLдокумента. Для начала рассмотрим пример XMLдо
кумента, полученного в результате вызова вебслужбы MathService –
получить эти данные можно с помощью дополнительного программно
го обеспечения, такого как инструмент Fiddler (http://www.fiddler
tool.com/fiddler) или расширение для Mozilla – Live HTTP Headers
(http://livehttpheaders.mozdev.org/):
<?xml version="1.0" encoding="utf 8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://
schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<DivideNumbersResponse xmlns="http://hauser wenz.de/AspNetAJAX/">
<DivideNumbersResult>0.857142866</DivideNumbersResult>
</DivideNumbersResponse>
</soap:Body>
</soap:Envelope>
:
<input type="text" id="b" name="b" size="2" />
=
<span id="c" style="width: 50px;"></span>
</nobr>
<br />
<input type="button" value="Divide Numbers"
onclick="callService(this.form);" />
</div>
</form>
</body>
</html>
);
soapcall.asyncInvoke(callComplete);
} catch (e) {
window.alert("Your browser is not supported.");
}
}
}
function callComplete(result, soapcall, status) {
if (result.value != null) {
document.getElementById("c").innerHTML = result.value;
} else {
document.getElementById("c").innerHTML =
result.body.firstChild.firstChild.firstChild.data;
}
}
</script>
</head>
<body>
<div id="WebService" style="behavior: url(webservice.htc);">
</div>
<form method="post" onsubmit="return false;">
<div>
<nobr>
<input type="text" id="a" name="a" size="2" />
:
<input type="text" id="b" name="b" size="2" />
= <span id="c" style="width: 50px;" ></span>
</nobr>
<br />
<input type="button" value="Divide Numbers"
onclick="callService(this.form);" />
</div>
</form>
</body>
</html>
Как показано на рис. 5.8 и 5.91, пример 5.9 работает в обоих основных
броузерах.
Подведение итогов
В этой главе был продемонстрирован ряд приемов работы с вебслуж
бами: сначала мы рассмотрели вопросы обработки ошибок и управле
ния состоянием сеанса, затем мы произвели обмен данными со слож
ной структурой между клиентом и вебслужбой. Наконец, мы рассмот
рели способы обращения к вебслужбам, построенным не на основе
ASP.NET, из JavaScript.
</form>
</body>
</html>
{
if (new Random().Next(0, 4) == 1) {
UpdatePanel1.Update();
}
}
Этот фрагмент обновляет панель (и изображение на экране, которое
видит пользователь) в среднем при каждом четвертом запросе. Компо
нент Timer вызывает обработчик события каждые пять секунд. После
этого программный код случайным образом определяет, следует ли
выполнить фактическое обновление панели в текущем вызове. В ре
альности вы бы скорее сначала проверили, изменились ли определен
ные данные (в базе данных или в файле), а затем при необходимости
включали обновление.
Элемент управления ASP.NET AJAX – UpdatePanel поддерживает два
режима работы, установить которые можно с помощью атрибута Upda
teMode:
Always
Содержимое элемента управления UpdatePanel будет обновляться
после каждой передачи данных (поведение по умолчанию).
Conditional
Содержимое элемента управления UpdatePanel будет обновляться
только при обработке событий, то есть при обращении к методу Up
date() (как в данном примере) или при обновлении родительской
панели, в которую вложен данный элемент UpdatePanel.
Вообще в режиме Conditional между сервером и клиентом передается
меньше данных, что способствует повышению производительности
элемента UpdatePanel. По этой причине всегда, когда это возможно (то
есть когда обновление панели происходит в результате обработки со
бытий или при непосредственном обращении к методу Update()), ис
пользуйте UpdateMode="Conditional".
В примере 6.3 демонстрируется полный программный код, управляю
щий обновлением элемента UpdatePanel, обновляемый через случайные
интервалы времени.
156 Глава 6. UpdatePanel: обновление только части страницы
endRequest
После того как запрос будет завершен.
initializeRequest
Запрос был инициализирован.
pageLoaded
Содержимое страницы было обновлено в результате запроса.
pageLoading
Данные от сервера были получены, но страница еще не обновля
лась.
Эти события возникают в следующем порядке:
initializeRequest, beginRequest, pageLoading, pageLoaded и endRequest.
Следующий пример предоставляет пользователю возможность щелч
ком на кнопке прервать затянувшийся запрос. Кнопка инициирует
отправку на сервер своих собственных данных. А для того, чтобы
инициализировать новый запрос, необходимо прервать исполнение
текущего. Чтобы обеспечить такое поведение, в обработчике события
initializeRequest необходимо выполнить некоторые действия:
var manager = Sys.WebForms.PageRequestManager.getInstance();
manager.add_initializeRequest(abortPendingPostback);
Функция JavaScript abortPendingPostback() автоматически получает
два аргумента (подобно методам обработки событий в .NET): объект,
который породил событие, и дополнительные аргументы, если они
имеются. В случае с классом PageRequestManager дополнительные аргу
менты имеют чрезвычайно важное значение. Для доступа к элементу,
инициировавшему отправку запроса, можно использовать метод
get_postBackElement().
Кроме того, могут пригодиться следующие два метода PageRequestMa
nager:
abortPostback()
Прерывает исполнение запроса
get_isInAsyncPostBack()
Проверяет, занят ли в настоящее время PageRequestManager обработ
кой асинхронного запроса
Эти методы делают возможным прерывание затянувшихся запросов.
Воспользуемся примером 6.4 в качестве отправной точки и добавим
новую кнопку для отмены запроса:
<asp:Button ID="Button2" runat="server"
Text="Abort postback" Style="display:none;" />
Когда произойдет щелчок на кнопке, которая запускает программный
код на сервере, должна сделаться видимой кнопка отмены:
Создание обновляемой области страницы 161
manager.add_initializeRequest(abortPendingPostback);
}
function abortPendingPostback(sender, eventArgs) {
var manager = Sys.WebForms.PageRequestManager.getInstance();
if (manager.get_isInAsyncPostBack() &&
eventArgs.get_postBackElement().getAttribute("id") == "Button2") {
manager.abortPostBack();
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Button ID="Button1" runat="server"
Text="Do something" OnClick="WaitFiveSeconds"
OnClientClick="$get('Button2').style.display='';" /><br />
<asp:Button ID="Button2" runat="server"
Text="Abort postback" Style="display:none;" />
<asp:Label ID="Label1" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdateProgress ID="UpdateProgress1" runat="server"
AssociatedUpdatePanelID="UpdatePanel1">
<ProgressTemplate>
<div style="position: absolute; left: 200px; top: 150px;
border: solid 2px black; padding: 4px;">
Loading, please stand by ...<br />
</div>
</ProgressTemplate>
</asp:UpdateProgress>
</form>
</body>
</html>
Подведение итогов
В этой главе была представлена одна из самых значимых возможно
стей ASP.NET AJAX: элемент управления UpdatePanel. Кроме того,
здесь были описаны сопутствующие ему компоненты Timer и UpdatePro
gress, из которых последний реализует экранную заставку, появляю
щуюся на время ожидания, – эффект, обычно используемый в Ajax
приложениях.
Для дополнительного чтения 163
Подготовка вебсайта
Чтобы пользоваться преимуществами, которые дает поддержка профи
лей в ASP.NET AJAX, ее сначала необходимо активировать. Для этого
в файле Web.config необходимо определить дополнительные элементы.
В узел <system.web> (по умолчанию уже имеется в файлах Web.config
сайтов, созданных из шаблона ASP.NET AJAX в среде Visual Studio) не
обходимо добавить элемент <profile>, где будет определяться набор
свойств, необходимых для работы вашего приложения. К слову – это
особенность не ASP.NET AJAX, а ASP.NET 2.0.
По умолчанию поддержка профилей в ASP.NET 2.0 действует только
для зарегистрированных пользователей. Однако, воспользовавшись
элементом <anonymousIdentification>, можно генерировать уникальные
ключи и для незарегистрированных пользователей с целью идентифи
цировать их данные профиля на стороне сервера:
<configuration>
[...]
<system.web>
<anonymousIdentification enabled="true" />
Объявить свойства для фактических данных профиля можно двумя
способами: в виде отдельных свойств или в виде групп свойств. В сле
дующем фрагменте показаны оба варианта: userName – это отдельное
свойство, и UserData – групповое свойство. Свойство UserData включает
в себя параметры myUserName и myPassword.
<profile>
<properties>
<add name="userName" allowAnonymous="true" />
<group name="UserData">
<add name="myUserName" allowAnonymous="true" />
<add name="myPassword" allowAnonymous="true" />
</group>
</properties>
</profile>
[...]
</system.web>
[...]
166 Глава 7. Использование службы управления профилями в ASP.NET AJAX
loadCompletedCallback
Метод, который необходимо вызвать в случае успешного окончания
загрузки профиля.
failedCallback
Метод, который необходимо вызвать в случае неудачного окончания
загрузки профиля (напоминает функцию обратного вызова, предна
значенную для обработки ошибок обращений к вебслужбам).
userContext
Необязательная информация, которая будет передана функциям об
ратного вызова.
После того как данные профиля будут загружены, доступ к этой ин
формации выполняется достаточно просто. Читать и записывать значе
ния свойств можно с использованием синтаксиса Sys.Services.Profile
Service.properties.<имя свойства> – при условии, что настройки в файле
Web.config позволяют это. В нашем примере для доступа к свойству
userName в профиле используется конструкция:
Sys.Services.ProfileService.properties.userName
Однако установка значения свойства в профиле на самом деле не при
водит к сохранению этой информации на сервере – она доступна лишь
сценарию JavaScript. Чтобы сохранить эту информацию, необходимо
вызвать метод save(), который ожидает получить четыре параметра, как
и метод load():
propertyNames
Имена сохраняемых свойств. Если в этом аргументе передать зна
чение null или пустую строку, на сервер будут выгружены все свой
ства, доступные клиентскому сценарию.
loadCompletedCallback
Метод, который необходимо вызвать в случае успешного сохране
ния профиля.
failedCallback
Метод, который необходимо вызвать в случае неудачного сохране
ния профиля.
userContext
Необязательная информация, которая будет передана функциям
обратного вызова.
Ниже демонстрируется пример использования этого прикладного ин
терфейса.
Форма регистрации, где вводится имя пользователя (и, возможно, па
роль), остается неизменной. Как обычно, сценарий начинается с эле
мента ScriptManager:
<asp:ScriptManager ID="ScriptManager1" runat="server" />
168 Глава 7. Использование службы управления профилями в ASP.NET AJAX
"change",
saveProfile);
Sys.Services.ProfileService.load(
null,
profileLoaded,
profileError,
"load");
}
function profileLoaded() {
$get("statusText").firstChild.nodeValue = "Profile data loaded.";
if (Sys.Services.ProfileService.properties.userName != null) {
$get("txtUsername").value =
Sys.Services.ProfileService.properties.userName;
}
}
function profileError(result, context) {
$get("statusText").firstChild.nodeValue =
"Could not " + context + " profile (" +
result.get_message() +
"). Check the configuration in web.config!";
}
function saveProfile() {
Sys.Services.ProfileService.properties.userName =
$get("txtUsername").value;
Sys.Services.ProfileService.save(
null,
profileSaved,
profileError,
"save");
}
function profileSaved() {
$get("statusText").firstChild.nodeValue = "Profile data saved.";
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
User name: <input type="text" id="txtUsername" runat="server" /><br />
Password: <input type="password" id="txtPassword" runat="server" />
<br />
<input type="button" id="Button1" runat="server" value="Login"
onclick="alert('not implemented!');" /><br />
<span id="statusText" runat="server"> </span>
</div>
</form>
</body>
</html>
Доступ к сгруппированным данным в профиле 171
Рис. 7.1. Теперь в поле User name сразу же загружается ранее введенное
имя пользователя
profileLoaded,
profileError,
{"operation": "load"});
В заключение необходимо изменить функцию profileError():
function profileError(result, context) {
$get("statusText").firstChild.nodeValue =
"Could not " + context.operation + " profile (" +
result.get_message() +
"). Check the configuration in web.config!";
}
Полный программный код этого приложения приводится в примере 7.2,
а на рис. 7.4 показан возможный результат.
Пример 7.2. Чтение и запись сгруппированных данных профиля
ProfileGroup.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN" "http://
www.w3.org/TR/
xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<script type="text/javascript">
function pageLoad() {
$addHandler(
$get("txtUsername"),
"change",
saveProfile1);
$addHandler(
$get("txtPassword"),
"change",
saveProfile2);
Sys.Services.ProfileService.load(
null,
profileLoaded,
profileError,
{"operation": "load"});
}
function profileLoaded() {
if (Sys.Services.ProfileService.properties.UserData != null) {
$get("statusText").firstChild.nodeValue = "Profile data loaded.";
$get("txtUsername").value =
Sys.Services.ProfileService.properties.UserData.myUserName;
$get("txtPassword").value =
Sys.Services.ProfileService.properties.UserData.myPassword;
} else {
Доступ к сгруппированным данным в профиле 175
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
User name: <input type="text" id="txtUsername" runat="server" /><br />
Password: <input type="password" id="txtPassword" runat="server" />
<br />
<input type="button" id="Button1" runat="server" value="Login"
onclick="alert('not implemented!');" /><br />
<span id="statusText" runat="server"> </span>
</div>
</form>
</body>
</html>
Примите к сведению: пароли никогда не должны храниться
в открытом виде. Механизм аутентификации ASP.NET 2.0 (ко
торый будет рассматриваться в следующей главе), например, по
умолчанию хранит пароли в зашифрованном виде. И хотя на
стороне клиента пароли не хранятся в открытом виде, на сторо
не сервера они могут оказаться незащищенными. Использова
ние протокола HTTPS позволит обезопасить хотя бы передачу
паролей.
Подведение итогов
В этой главе была использована служба управления профилями –
ASP.NET 2.0 Profile Service, причем без применения серверных сцена
риев. Вместо этого был использован прикладной интерфейс Java
Script, предоставляемый ASP.NET AJAX для доступа к данным про
филя с применением исключительно клиентского сценария.
Подготовка приложения
Чтобы иметь возможность использовать службу аутентификации
ASP.NET AJAX, необходимо добавить пользователей в приложение.
Сделать это можно с помощью такого инструмента, как ASP.NET Web
Application Administration Tool, который поставляется в составе Visu
al Studio и Visual Web Developer. Сначала запустите команду ASP.NET
Configuration (настройка ASP.NET) в меню Web Site, как показано на
рис. 8.1.
178 Глава 8. Использование службы аутентификации в ASP.NET AJAX
Вход и выход
Поддержка механизма ASP.NET AJAX Forms Authentication осущест
вляется двумя методами класса Sys.Services.AuthenticationService: log
in() и logout(). Начнем с операции входа пользователя. При вызове
этому методу должно быть передано не менее восьми параметров:
userName
Имя пользователя
password
Пароль
isPersistent
Должен ли cookie системы аутентификации постоянно храниться
на стороне клиента (по умолчанию false)
redirectUrl
Адрес URL, куда должен быть перенаправлен броузер после входа
пользователя, или null, если перенаправление не требуется (по
умолчанию)
customInfo
В настоящее время не используется
loginCompletedCallback
Функция, которая вызывается после успешного входа
failedCallback
Функция, которая вызывается в случае неудачной попытки входа
userContext
Данные, которые передаются функциям обратного вызова
Существуют два варианта реализации процедуры аутентификации:
1. Вызвать метод login() и разрешить JavaScript выполнить перена
правление на другую страницу, установив значение аргумента redi
rectUrl.
2. Вызвать метод login() и с помощью функций обратного вызова
loginCompletedCallback() и failedCallback() обработать результаты
аутентификации.
Чаще на практике используется второй вариант. Перенаправление
упирается в проблему безопасности данных в JavaScript, который, как
уже говорилось, не обеспечивает достаточный уровень безопасности.
Вход и выход 181
$get("txtUsername").value,
$get("txtPassword").value,
false,
null,
null,
loginComplete,
loginError,
"login");
break;
case "Logout":
Sys.Services.AuthenticationService.logout(
null,
loginComplete,
loginError,
"logout");
break;
}
}
Функция loginError() обрабатывает такие ошибки при входе и выходе,
как неверное имя пользователя или пароль, отсутствие имени пользо
вателя или неправильные настройки на сервере. Соответствующее со
общение об ошибке будет отображаться в метке HTML:
function loginError(result, context) {
$get("statusText").firstChild.nodeValue =
"Could not " + context + " (" +
result.get_message( ) + ").";
}
Наконец, функция loginComplete() выводит сообщение о состоянии опе
рации. Кроме того, она изменяет форму регистрации. После успешного
входа пользователя оба текстовых поля делаются недоступными для
ввода, а надпись "login" на кнопке изменяется на "logout". После того
как пользователь совершит выход, надпись на кнопке опять изменится
на "login", а оба текстовых поля станут доступными для ввода.
function loginComplete(result, context) {
switch (context) {
case "login":
if (result == true) {
$get("txtUsername").disabled = true;
$get("txtPassword").disabled = true;
$get("Button1").value = "Logout";
$get("statusText").firstChild.nodeValue = "Logged in";
} else {
$get("statusText").firstChild.nodeValue = "Login failed";
}
break;
case "logout":
$get("txtUsername").disabled = false;
$get("txtPassword").disabled = false;
Вход и выход 183
$get("Button1").value = "Login";
$get("statusText").firstChild.nodeValue = "Logged out";
break;
}
}
Полный программный код этого примера приводится в примере 8.1.
Не забудьте внести в файл Web.config необходимые изменения, прежде
чем опробовать этот пример.
Пример 8.1. Аутентификация пользователя с помощью JavaScript
Authentication.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/ xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<script type="text/javascript">
function pageLoad( ) {
$addHandler(
$get("Button1"),
"click",
doClick);
$addHandler(
$get("txtUsername"),
"change",
saveProfile1);
$addHandler(
$get("txtPassword"),
"change",
saveProfile2);
Sys.Services.ProfileService.load(
"",
profileLoaded,
profileError,
{"operation": "load"});
}
function profileLoaded( ) {
if (Sys.Services.ProfileService.properties.UserData != null) {
$get("statusText").firstChild.nodeValue = "Profile data loaded.";
$get("txtUsername").value =
Sys.Services.ProfileService.properties.UserData.myUserName;
$get("txtPassword").value =
Sys.Services.ProfileService.properties.UserData.myPassword;
} else {
$get("statusText").firstChild.nodeValue = "No data available.";
}
}
184 Глава 8. Использование службы аутентификации в ASP.NET AJAX
Подведение итогов
В этой главе было продемонстрировано использование механизма аутен
тификации ASP.NET 2.0 без применения какоголибо программного
кода на стороне сервера. Все, что было нами использовано, – это Java
186 Глава 8. Использование службы аутентификации в ASP.NET AJAX
Локализация
Локализация вебсайта – это процесс адаптации содержимого к регио
нальным настройкам системы, чаще всего – к региональным настрой
кам пользователя. Часто локализация как таковая обозначается аббре
виатурой l10n, которая происходит от обозначения «l, затем 10 симво
лов, затем n»1 (так называемый нумероним).
На любом вебсайте имеются самые разные разделы, которые могли бы
быть локализованы. И сам текст на сайте, и название валюты, и фор
мат представления даты и времени – все это может быть локализовано.
В платформе ASP.NET имеется ряд возможностей по обеспечению ло
кализации (некоторые ссылки вы найдете в разделе «Для дополни
тельного чтения» в конце главы). Некоторые из этих возможностей ис
пользуются платформой ASP.NET AJAX для организации поддержки
локализации в программном коде JavaScript.
Локализация сценариев
Самый простой способ локализации состоит в том, чтобы написать спе
циализированный сценарий, который будет решать поставленную за
дачу. Например, этот сценарий мог бы определять региональные на
стройки и затем загружать ту или иную библиотеку. Половину этой
задачи можно решить средствами ASP.NET, а вторую половину – сред
ствами ASP.NET AJAX.
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"
msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string"
msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string"
msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"
msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="dateformat" xml:space="preserve">
<value>ss, dd.mm.yyyy</value>
</data>
<data name="daynames" xml:space="preserve">
<value>["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag",
"Freitag", "Samstag"]</value>
</data>
<data name="loading" xml:space="preserve">
<value>Lade Datum ...</value>
</data>
</root>
Из этого XMLфайла видно, какая информация помещается в файлы
ресурсов:
Локализация 197
dateformat
Формат представления даты с использованием символовзаполни
телей
daynames
Локализованные названия дней недели
loading
Текст «Loading date...» (загрузка даты), переведенный на отдель
ные языки
Вам необходимо создать как минимум два файла ресурсов (для анг
лийского и немецкого языков). По своему желанию вы можете доба
вить локализации и для других языков. Для определения названий
дней недели используйте синтаксис массивов в формате JSON (глава 3).
Будьте внимательны и старайтесь не допускать опечаток, так как при
ложения, состоящие из серверных и клиентских сценариев, а также
ресурсов, очень сложно отлаживать.
В окне Solution Explorer (обозреватель решений) в текущем проекте от
кройте папку Properties (свойства). Внутри нее вы найдете файл Assemb
lyInfo.cs, в котором содержится дополнительная информация о проек
те. Если вы не видите этот файл, щелкните на кнопке Show All Files
(показать все файлы), как показано на рис. 9.5.
В конец файла AssemblyInfo.cs добавьте следующие строки:
[assembly: System.Web.UI.WebResource("LocalizedDate.Dayname.js",
"application/xjavascript")]
[assembly: System.Web.UI.ScriptResource("LocalizedDate.Dayname.js",
"LocalizedDate.DateResources", "LocData")]
Обратите внимание на значение LocData в последнем аргументе. Это
имя позволит обращаться ко всем данным в файле ресурсов из про
граммного кода JavaScript посредством объекта LocData. Имя может
выбираться совершенно произвольно, но это имя будет использоваться
в следующих примерах.
Остальные значения в предыдущем фрагменте содержат данные,
имеющие отношение к приложению. LocalizedDate – это имя проекта,
Dayname.js – это файл JavaScript, который будет создан на следующем
шаге, а DateResources будет использоваться позже для организации дос
тупа к данным в файле ресурсов (из программного кода на C#).
Файл Dayname.js содержит программный код JavaScript, который оп
ределяет текущую дату и форматирует ее в соответствии с текущими
региональными настройками. Как уже говорилось выше, объект Loc
Data используется в JavaScript для доступа к информации из файла ре
сурсов. Свойство LocData.dateformat содержит строку формата даты,
а свойство LocData.daynames – массив с названиями дней недели. По
следнее значение хранится в формате JSON (глава 3), поэтому нам
придется использовать функцию eval() для преобразования строки
в объект JavaScript:
var daynames = eval("(" + LocData.daynames + ")");
Программный код в Dayname.js, подобный тому, что приводился в при
мере 9.3, будет замещать символызаполнители в строке dateformat
и отображать результат в окне броузера. Обратите внимание на односе
кундную задержку, которая была добавлена для того, чтобы сделать
эффект более наглядным. В примере 9.5 приводится полный про
граммный код файла JavaScript. Добавьте его в свой проект.
Пример 9.5. Программный код JavaScript в библиотеке классов
Dayname.js
Sys.Application.add_load(function() {
var d = new Date();
var daynames = eval("(" + LocData.daynames + ")");
var datestring = LocData.dateformat.replace("ss", daynames[d.getDay()])
.replace("dd", d.getDate())
.replace("mm", d.getMonth() + 1)
.replace("yyyy", d.getFullYear());
setTimeout('$get("date").firstChild.nodeValue = "'
+ datestring + '"', 1000);
});
В заключение файл Dayname.js необходимо встроить в сборку. Щелк
ните на имени файла в окне Solution Explorer (обозреватель решений).
Локализация 199
В элементе <span> будет находиться текст «Loading date...» или тот, ко
торый задан для выбранного языка. Чтобы получить нужную строку,
</body>
</html>
Глобализация и интернационализация
В дополнение к поддержке локализации, ASP.NET AJAX предостав
ляет поддержку глобализации, которую иногда еще называют как ин
тернационализация (или i18n, если вам нравится использовать нуме
ронимы). В элементе управления ScriptManager имеется свойство Enab
leScriptGlobalization. Если в этом свойстве установить значение true,
ASP.NET AJAX будет в состоянии локализовать значения дат. Для
этого библиотека Ajax расширяет возможности объекта Date из Java
Script (и других объектов – подробности в главе 4 и в приложении D),
благодаря чему в этом объекте появился новый метод с именем locale
Format(). Этот метод форматирует значение даты в соответствии с ре
гиональными настройками в броузере. Эти настройки передаются
в HTTPзаголовке Accept Language. На рис. 9.9 показаны HTTPзаго
ловки, отправляемые броузером Firefox с настройками для немецкого
языка. Обратите внимание: заголовок Accept Language включает пере
чень поддерживаемых языков в сответствии с уровнем их предпочте
ния. На этой иллюстрации видно, что немецкий язык является наибо
лее предпочтительным, вслед за ним идет английский язык. В англо
язычных броузерах обычно предпочтительным является только анг
лийский язык, иногда учитываются различия между американским,
<title>ASP.NET AJAX</title>
<script type="text/javascript">
function pageLoad() {
$get("date").firstChild.nodeValue =
(new Date()).localeFormat("dddd, dd. MMMM yyyy");
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"
EnableScriptGlobalization="true">
</asp:ScriptManager>
<div>
<span id="date"> </span>
</div>
</form>
</body>
</html>
На рис. 9.12 показаны результаты работы этой страницы на немецком
языке, а на рис. 9.13 – на французском. В обоих случаях эти результаты
Подведение итогов
В век глобализации вебсайты должны обеспечивать возможность взаи
модействия с пользователями из разных стран, которые говорят на раз
ных языках. В этой главе были продемонстрированы некоторые прие
мы создания многоязычных вебсайтов с использованием ASP.NET
AJAX.
Рис. 10.3. Мастер установки пакета интеграции VSI для работы с пакетом
Control Toolkit
Теперь создадим новый вебсайт в среде Visual Studio или Visual Web
Developer Express Edition, используя для этого шаблон AJAX Control
Toolkit Web Site (рис. 10.4).
Подведение итогов
В этой главе мы познакомились с пакетом ASP.NET AJAX Control
Toolkit, установили его и рассмотрели первый пример. В следующих
главах будет рассказываться о наиболее интересных компонентах
и особенностях, реализованных в этом проекте с открытыми исходны
ми текстами.
Для дополнительного чтения 219
Основы анимации
Платформа создания анимационных эффектов пакета Control Toolkit
содержит элемент AnimationExtender. Самое первое свойство, которое
вам потребуется, – это TargetControlID, в нем должно содержаться зна
чение атрибута ID анимируемого элемента:
<ajaxToolkit:AnimationExtender ID="AnimationExtender1" runat="server"
TargetControlID="myTargetElement">
<! ... >
</ajaxToolkit:AnimationExtender>
Фактическое определение анимационного эффекта располагается внут
ри элемента AnimationExtender. Здесь вы размещаете разметку XML, ко
торая будет управлять анимацией. Корневым элементом этой размет
ки является элемент <Animations>. Внутри этого узла должна быть оп
ределена следующая информация:
События
Когда запускать анимацию, то есть – событие
Типы и свойства анимации
Какие анимационные эффекты будут использоваться: плавное ис
чезновение, перемещение, изменение размеров или какието еще
(подробнее о них будет говориться чуть ниже)
Пример 11.1 демонстрирует создание анимационного эффекта. Анима
ционный эффект представлен в виде узла <OnLoad>, расположенного
внутри узла <Animation>, который будет запускаться по окончании пол
ной загрузки страницы. В данном случае в элементе <OnLoad> описывает
ся единственный анимационный эффект – элемент <FadeOut>. В резуль
тате целевой элемент будет постепенно исчезать в течение трех секунд
(атрибут Duration), минуя 25 градаций уровня прозрачности в секунду
(атрибут Fps [frames per second – кадров в секунду]). На рис. 11.1 показа
но окно броузера в середине воспроизведения анимационного эффекта.
Пример 11.1. Простейший эффект плавного исчезновения
AnimationFade.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
222 Глава 11. Добавление анимационных эффектов в веб"страницу
<OnMouseOver>
Анимация запускается в момент, когда указатель мыши попадает
в пределы элемента. (Но при этом любые анимационные эффекты,
запущенные по событию <OnHoverOut>, не останавливаются.)
</Animations>
</ajaxToolkit:AnimationExtender>
</form>
</body>
</html>
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
<asp:Label ID="Label1" runat="server" Text="See me fading ..."
Style="display: inline block; background color: Red; position:
relative; left: 8px; top: 8px;" />
</div>
<ajaxToolkit:AnimationExtender ID="AnimationExtender1" runat="server"
TargetControlID="Label1" />
</form>
</body>
</html>
То же самое можно сделать и в сценарии JavaScript. Единственная
разница заключается в формате представления описания анимацион
ного эффекта. Вместо строки в формате XML необходимо использовать
строку в формате JSON. Вся информация об анимационном эффекте
содержится в виде объекта, представленного строкой JSON. Имя ани
мационного эффекта (которое идентично имени соответствующего эле
мента XML) определяется с помощью свойства AnimationName. Элемен
ты внутри элемента XML оформляются в виде массива с помощью
свойства AnimationChildren. Ниже приводится только строка в формате
JSON, отформатированная для лучшего восприятия:
{
'AnimationName':'Parallel',
'AnimationChildren':
[
{
'AnimationName':'FadeOut',
'Duration':'3',
'Fps':'25'
},
{
'AnimationName':'Condition',
'ConditionScript':'(Math.random( ) < 0.5)',
'AnimationChildren':
[
{
'AnimationName':'Length',
'StartValue':'0',
'EndValue':'250',
'Unit':'px',
'Property':'style',
228 Глава 11. Добавление анимационных эффектов в веб"страницу
'PropertyKey':'left'
},
{
'AnimationName':'Length',
'StartValue':'0',
'EndValue':'250',
'Unit':'px',
'Property':'style',
'PropertyKey':'top'
}
]
}
]
}
Кроме того, вам может потребоваться средство доступа к элементам
управления в странице, поскольку сам по себе элемент AnimationExten
der не имеет визуального представления. Платформа ASP.NET AJAX
предоставляет вспомогательную функцию $find(), которая позволяет
получить доступ к подобным элементам управления. Получив с ее по
мощью ссылку на требуемый элемент управления, можно связать
строку в формате JSON с одним из анимационных событий. Напри
мер, метод set_OnClick() позволяет назначить запуск анимационного
эффекта по щелчку на анимированном элементе.
В примере 11.4 приводится полный программный код. Результат рабо
ты этого примера тот же самый, что и в примерах 11.2 и 11.2, но на этот
раз анимационный эффект описывается внутри клиентского сценария.
Пример 11.4. Воспроизведение анимации с использованием программного
кода на стороне клиента
AnimationClient.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<script type="text/javascript">
function pageLoad( ) {
var animations =
"{'AnimationName':'Parallel','AnimationChildren':
[{'AnimationName':'FadeOut','Duration':'3','Fps':'25'},
{'AnimationName':'Condition','ConditionScript':
'(Math.random( ) < 0.5)','AnimationChildren':
[{'AnimationName':'Length','StartValue':'0',
'EndValue':'250','Unit':'px','Property'
:'style','PropertyKey':'left'},
{'AnimationName':'Length','StartValue':'0',
Перетащить"и"отпустить 229
'EndValue':'250','Unit':'px','Property':
'style','PropertyKey':'top'}]}]}";
var extender = $find("AnimationExtender1");
extender.set_OnLoad(animations);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
<asp:Label ID="Label1" runat="server" Text="See me fading ..."
Style="display: inline block; background color: Red;
position: relative; left: 8px; top: 8px;" />
</div>
<ajaxToolkit:AnimationExtender ID="AnimationExtender1" runat="server"
TargetControlID="Label1" />
</form>
</body>
</html>
Платформа создания анимационных эффектов обладает еще целым
рядом возможностей. В дополнение к тем что были продемонстрирова
ны в этой главе, она допускает расширение, обеспечивая большую гиб
кость и принимая на себя существенную долю труда программиста по
написанию программного кода JavaScript. Те, кого это заинтересова
ло, найдут массу справочной информации и разбор программ на сайте
с примерами использования компонентов из пакета ASP.NET AJAX
Control Toolkit (который называется SampleWebsite).
Перетащитьиотпустить
Реализация техники перетащитьиотпустить (draganddrop) считает
ся одной из самых сложных задач для разработчиков на JavaScript.
Поддержкой техники перетащитьиотпустить обладают все броузеры,
но слишком велики различия в тонкостях ее реализации для разных ти
пов броузеров. К счастью, в состав пакета ASP.NET AJAX Control Tool
kit входит расширитель DragPanel, который дополняет компонент
ASP.NET Panel возможностью «перетаскивания». Чтобы сделать эле
менты доступными для перетаскивания, достаточно просто поместить
их в элемент <asp:Panel> и добавить в страницу компонент DragPanelEx
tender. Затем требуется задать следующие свойства элементарасшири
теля:
TargetControlID
Значение атрибута ID элемента Panel
230 Глава 11. Добавление анимационных эффектов в веб"страницу
DragHandleID
Значение атрибута ID элемента, выступающего в роли «рукоятки»,
за которую можно будет «ухватиться» мышью (в идеале должен
размещаться внутри перетаскиваемой панели)
В примере 11.5 имеется две панели: одна содержит некоторый текст,
а другая содержит информацию о получении случайного числа новых
писем в почтовом ящике. Эта вторая панель может перетаскиваться
мышью благодаря использованию элемента управления DragPanelEx
tender. На рис. 11.3 показан конечный результат.
Пример 11.5. Создание «перетаскиваемой» панели
DragPanel.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
inbox.Text = new Random().Next(0, 100).ToString( );
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
Перетащить"и"отпустить 231
<style type="text/css">
.box { border: solid 2px black; }
.mailbox { border: solid 2px black; width: 150px;
background color: white;}
.mailboxHeader {border: solid 2px black; background color: blue;
font weight: bold; cursor: move;}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div style="height: 400px; background color: purple">
<asp:Panel ID="ContentPanel" CssClass="box" runat="server">
<h1>My Portal</h1>
<p>
Welcome to your personal portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable. Welcome to your personal
portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable. Welcome to your personal
portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable.
</p>
<p>
Welcome to your personal portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable. Welcome to your personal
portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable. Welcome to your personal
portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable.
</p>
<p>
Welcome to your personal portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable. Welcome to your personal
portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable. Welcome to your personal
portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable.
</p>
</asp:Panel>
<asp:Panel CssClass="mailbox" ID="DragPanel" runat="server">
<div id="DragPanelHandle" runat="server"
class="mailboxHeader">New mail!</div>
<p>
You currently have <asp:Label id="inbox"
runat="server"></asp:Label>
mails in your <a href="http://www.hotmail.com/">inbox</a>.
</p>
</asp:Panel>
<ajaxToolkit:DragPanelExtender ID="DragPanelExtender1" runat="server"
TargetControlID="DragPanel" DragHandleID="DragPanelHandle" />
232 Глава 11. Добавление анимационных эффектов в веб"страницу
</div>
</form>
</body>
</html>
Подведение итогов
Не всякое вебприложение становится лучше от добавления анимаци
онных эффектов. Однако если они действительно необходимы, попро
буйте воспользоваться платформой Animation, входящей в состав паке
та ASP.NET AJAX Control Toolkit. А если требуется реализация тех
ники перетащитьиотпустить (draganddrop) – обратите внимание на
расширитель DragPanel.
<Header>Ajax</Header>
<Content>Chapter 3 explains the technologies beyond the hype.
You learn what happens in the background, how Ajax works, and what it really
is all about, in fewer than 20 pages.</Content>
</ajaxToolkit:AccordionPane>
</Panes>
</ajaxToolkit:Accordion>
</div>
</form>
</body>
</html>
Управление относительным
положением элемента
Каскадные таблицы стилей (CSS) позволяют позиционировать HTML
элементы в любом месте страницы с помощью координат x и y. Однако
положение элемента управления может изменяться при прокрутке
страницы пользователем. Добавив немного программного кода Java
Script, можно обеспечить неизменное положение элемента в окне бро
узера, независимо от того, в какую сторону пользователь выполняет
прокрутку.
Как вы наверное и ожидали, ASP.NET AJAX Control Toolkit предлага
ет свое решение этой задачи – элемент управления AlwaysVisibleControl
Extender. Этот расширитель может быть подключен к любому элементу
управления, чтобы обеспечить ему неизменность положения относи
тельно границ окна броузера. Например, свойство HorizontalSide рас
ширителя может принимать значения Center, Left и Right, а свойство
VerticalSide – значения Top, Middle или Bottom. Имеется также возмож
ность указать величину смещения относительно левой и верхней гра
ницы окна броузера с помощью свойств HorizontalOffset и VerticalOff
set. Ниже приводится пример разметки расширителя, который пози
ционирует элемент HTML в верхнем левом углу окна броузера:
<ajaxToolkit:AlwaysVisibleControlExtender ID="AlwaysVisibleControlExtender1"
runat="server" TargetControlID="banner" HorizontalSide="Left"
VerticalSide="Top" />
В примере 12.2 содержится полный исходный код, а результат его ра
боты приводится на рис. 12.2. На рисунке видно, что баннер остается
в верхнем левом углу окна и при прокрутке страницы.
Пример 12.2. Использование AlwaysVisibleControlExtender
AlwaysVisible.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
Добавление функции автодополнения к элементу управления TextBox 237
Рис. 12.2. Баннер остается в верхнем левом углу окна даже после
прокрутки страницы
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div id="banner" style="background color: white; border: solid; width:
240px; height: 80px;" runat="server">
<h2>And here is from our sponsors ...</h2>
</div>
<ajaxToolkit:AlwaysVisibleControlExtender ID="
AlwaysVisibleControlExtender1" runat="server"
TargetControlID="banner" HorizontalSide="Left" VerticalSide="Top" />
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
<p>Welcome to the ASP.NET AJAX Control Toolkit sample website. </p>
</form>
</body>
</html>
TargetControlID="vendor" />
</form>
</body>
</html>
Кромет того, вам необходимо реализовать вебслужбу, которая возвра
щала бы необходимые данные. Вебслужба должна включать метод
с определенной сигнатурой, который будет вызываться расширите
лем. Сигнатура метода приводится ниже:
public string[] <MethodName>(string prefixText, int count)
Метод принимает два параметра, назначение которых достаточно оче
видно:
prefixText
Текст, введенный пользователем в текстовое поле, который будет
использоваться в качестве префикса для всех совпадений
count
Максимальное число возвращаемых результатов
Данные должны возвращаться в виде массива строк, поэтому, к сожа
лению, вы не можете использовать наборы записей из базы данных
или нечто похожее.
В примере вебслужбы для реализации функции автодополнения ис
пользуется база данных AdventureWorks. В качестве результата кли
енту возвращаются названия компаний всех производителей. Как
обычно, вам придется адаптировать строку подключения под свои ус
ловия – в программном коде предполагается, что SQL Server 2005 Ex
press Edition доступен с использованием типа аутентификации Win
dows и строкой подключения (local)\SQLEXPRESS.
Сначала программный код вебслужбы проверяет строку поиска. Для
простоты примера будем считать допустимыми только символы от a до z
(верхнего и нижнего регистров). Эта проверка необходима для предот
вращения инъекции SQLкода, потому что программа будет запускать
поисковый запрос, содержащий выражение LIKE (подробнее об этом го
ворится во врезке «Внимание: опасайтесь инъекции SQLкода»). В ка
честве альтернативы можно использовать параметризованные запросы.
Рис. 12.4. Инструменты, такие как Live HTTP headers, позволяют сделать
тайное явным
Рис. 12.9. Сервер отверг данные, поскольку они были отправлены несколько
раз за слишком короткий промежуток времени
254 Глава 12. Автодополнение ввода пользователя, борьба со спамом и не только
Подведение итогов
В этой главе говорилось о различных элементах управления из пакета
ASP.NET AJAX Control Toolkit. В состав этого пакета входит еще мно
го других компонентов и с каждой новой версией в нем появляются но
вые компоненты и новые возможности, поэтому старайтесь чаще посе
щать домашнюю страницу проекта Control Toolkit!
Для дополнительного чтения 257
Как вы уже видели в главах 10, 11 и 12, пакет ASP.NET AJAX Control
Toolkit предлагает множество самых разнообразных элементов управ
ления. В этой главе мы продвинемся еще на один шаг и посмотрим,
как можно использовать инфраструктуру пакета для создания своих
собственных элементов управления. Кроме того, здесь вы узнаете, как
можно оказать содействие сообществу Control Toolkit.
using System.Web.UI;
namespace TextBoxMask
{
class TextBoxMaskDesigner : AjaxControlToolkit.Design.
ExtenderControlBaseDesigner<TextBoxMaskExtender>
{
}
}
Файл TextBoxMaskExtender.cs содержит информацию о расширителе
для конструктора. Как видно из примера 13.2, в программном коде
имеется ссылка на файл TextBoxMaskBehavior.js. По умолчанию для
элементов, используемых совместно с этим расширителем, выбран тип
данных Control. Однако мы предполагаем расширять текстовое поле,
поэтому измените тип Control на TextBox.
[TargetControlType(typeof(TextBox))]
Далее в файле вы можете увидеть единственное свойство, присутст
вующее в шаблоне: MyProperty. Удалите этот член класса и создайте
строковое свойство ValidChars с соответствующими методами доступа.
Позднее в этом свойстве будут храниться символы, допустимые для
ввода в текстовое поле.
В качестве методов доступа к значению свойства будут использоваться
функции GetPropertyValue() и SetPropertyValue(). Кроме того, установи
те атрибут DefaultProperty, чтобы сделать ValidChars свойством расши
рителя по умолчанию. Полный программный код представлен в при
мере 13.2.
Пример 13.2. Класс TextBoxMaskExtender
TextBoxMaskProperties.cs
using System;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.ComponentModel;
using System.ComponentModel.Design;
using AjaxControlToolkit;
[assembly: System.Web.UI.WebResource("TextBoxMask.TextBoxMaskBehavior.js",
"text/javascript")]
namespace TextBoxMask
{
[Designer(typeof(TextBoxMaskDesigner))]
[ClientScriptResource("TextBoxMask.TextBoxMaskBehavior",
"TextBoxMask.TextBoxMaskBehavior.js")]
[TargetControlType(typeof(TextBox))]
[DefaultProperty("ValidChars")]
public class TextBoxMaskExtender : ExtenderControlBase
{
262 Глава 13. Создание собственных элементов управления и помощь сообществу
TextBoxMask.TextBoxMaskBehavior.prototype = {
initialize : function( ) {
TextBoxMask.TextBoxMaskBehavior.callBaseMethod(this, 'initialize');
// TODO: добавьте сюда код инициализации
this._keydownHandler = Function.createDelegate(this, this._onkeydown);
$addHandler(this.get_element( ), "keydown", this._keydownHandler);
},
dispose : function( ) {
// TODO: добавьте сюда код, освобождающий ресурсы
$removeHandler(this.get_element( ), "keydown", this._keydownHandler);
this._keydownHandler = null;
TextBoxMask.TextBoxMaskBehavior.callBaseMethod(this, 'dispose');
},
_onkeydown : function(e) {
var key = e.rawEvent.keyCode;
if (key >= 96 && key <= 105) {
key = 48;
}
if (key == 8 || key == 9 || key == 16
|| (key >= 35 && key <= 40) || key == 45 || key == 46
|| this._validChars.indexOf(String.fromCharCode(key)) != 1) {
return true;
} else {
e.preventDefault( );
return false;
}
},
// TODO: (Этап 2) Добавьте здесь методы доступа к свойствам
//
get_ValidChars : function( ) {
return this._validChars;
},
set_ValidChars : function(value) {
this._validChars = value;
}
}
TextBoxMask.TextBoxMaskBehavior.registerClass(
'TextBoxMask.TextBoxMaskBehavior',
AjaxControlToolkit.BehaviorBase);
Теперь давайте соберем проект. В результате будет создан файл Text
BoxMask.dll, куда будет включен файл .js в виде внедренного ресурса,
доступного для элемента управления ScriptManager на этапе исполне
ния. Обычно расширитель TextBoxMask появляется в палитре компонен
тов автоматически. Но добавлять его в проект вебсайта придется
266 Глава 13. Создание собственных элементов управления и помощь сообществу
Подведение итогов
В этой главе вы узнали, как установить и использовать пакет
ASP.NET AJAX Control Toolkit. Вы также узнали, как с помощью па
кета создать свой собственный элемент управления. Измененная и до
полненная версия примера, приведенного в этой главе, в настоящее
время вошла в состав пакета. Отыщите компонент FilteredTextBox и ис
пытайте его в деле!
278 Глава 13. Создание собственных элементов управления и помощь сообществу
Sys.Preview.UI.Window.messageBox("Using Sys.Preview.UI.Window");
}
function MessageBoxOKCancelClick() {
Sys.Preview.UI.Window.messageBox("Using Sys.Preview.UI.Window",
Sys.Preview.UI.MessageBoxStyle.OKCancel);
}
function InputBoxClick() {
Sys.UI.Window.inputBox("Using Sys.Preview.UI.Window", "<enter text here>");
}
</script>
Для использования функциональности ASP.NET AJAX к странице не
обходимо подключить библиотеку ASP.NET AJAX. Все, что необходи
мо, возьмет на себя элемент ScriptManager:
<asp:ScriptManager runat="server">
Он загрузит базовую библиотеку ASP.NET AJAX. Однако, чтобы ис
пользовать компоненты адресного пространства Sys.Preview.UI, необ
ходимо загрузить еще и библиотеку Futures. В отличие от базовой эту
библиотеку придется загружать вручную, используя следующий син
таксис:
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
В примере 14.1 приводится полный программный код первого примера
использования ASP.NET AJAX в этой главе. Не забудьте, чтобы иметь
возможность использовать пакет Futures и сборку Sys.Preview.UI, вы
должны создавать вебсайт, настроенный на использование функцио
нальности Futures. О том, как это делается, рассказывается в главе 1.
Пример 14.1. Модальные панели JavaScript средствами ASP.NET AJAX
ControlMessageBox.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
<script language="JavaScript" type="text/javascript">
function MessageBoxOKClick() {
Sys.Preview.UI.Window.messageBox("Using Sys.Preview.UI.Window");
}
function MessageBoxOKCancelClick() {
Sys.Preview.UI.Window.messageBox("Using Sys.Preview.UI.Window",
Sys.Preview.UI.MessageBoxStyle.OKCancel);
}
Использование элементов управления ASP.NET AJAX 285
function InputBoxClick() {
Sys.Preview.UI.Window.inputBox("Using Sys.Preview.UI.Window",
"<enter text here>");
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="button" value="MessageBoxOK"
onclick="MessageBoxOKClick();" />
<input type="button" value="MessageBoxOKCancel"
onclick="MessageBoxOKCancelClick();" />
<input type="button" value="InputBox" onclick="InputBoxClick();" />
</div>
</form>
</body>
</html>
На рис. 14.1 показан результат щелчка на кнопке InputBox1.
Рассмотренные возможности достаточно удобны, но они не представ
ляют собой ничего особенного – это самая обычная функциональность
JavaScript, обернутая в элементы управления ASP.NET AJAX. Одна
ко существуют и другие элементы управления, которые обладают бо
лее широкими возможностями.
Затем можно задать значения для свойств этого элемента, включая ин
формацию о стилях. При использовании JavaScript вам пришлось бы
писать отдельный код для разных броузеров. А для этого, как уже от
мечалось ранее, требуется основательное знание JavaScript и DOM –
простого знания синтаксиса будет недостаточно.
В ASP.NET AJAX используется иной подход. Вы должны знать свой
ства и методы класса, соответствующего клиентскому элементу управ
ления ASP.NET AJAX, и не более того (просмотрите еще раз содержи
мое табл. 14.1). В нашем случае с элементом <span> используется класс
Sys.Preview.UI.Label. Программный код должен создать экземпляр это
го класса и передать ему значение атрибута ID HTMLэлемента. Значе
ние ID должно быть задано определенным образом: с помощью упоми
навшегося выше метода $get() с фактическим значением ID в скобках:
var label = new Sys.Preview.UI.Label($get("Label1"));
Метки
Элемент управления ASP.NET AJAX – Label поддерживает два допол
нительных метода, описываемых ниже. Оба они демонстрируются
в примере 14.2.
get_text()
Возвращает текущий текст из элемента
set_text()
Записывает (изменяет) текст в элемент
</Scripts>
</asp:ScriptManager>
<div>
<span id="Label1">time goes here: </span>
</div>
</form>
</body>
</html>
После загрузки страницы определяется текущее время и его значение
помещается в элемент <span>. На рис. 14.2 показан результат работы
примера. Чтобы увидеть новое значение времени, достаточно обновить
страницу в броузере.
Изображения
Изображения на странице представляет HTMLтег <img>. Класс Sys.Pre
view.UI.Image реализует ASP.NET AJAXверсию изображения (пред
ставленного в дереве DOM объектом Image). Кроме обычных методов,
перечисленных ранее, класс ASP.NET AJAX Image поддерживает сле
дующие дополнительные методы:
get_alternateText()
Возвращает значение атрибута alt
set_alternateText()
Изменяет значение атрибута alt
get_height()
Возвращает высоту изображения
set_height()
Изменяет высоту изображения
get_width()
Возвращает ширину изображения
Использование элементов управления ASP.NET AJAX 289
set_width()
Изменяет ширину изображения
get_imageURL()
Возвращает относительный или абсолютный адрес URL изображе
ния (атрибут src)
set_imageURL()
Изменяет относительный или абсолютный адрес URL изображения
(атрибут src)
Здесь также стандартные свойства DOM инкапсулированы в состав
класса. Вам не нужно обладать глубокими познаниями JavaScript,
достаточно лишь привыкнуть к использованию методов, предлагае
мых платформой ASP.NET AJAX. Пример 14.3 показывает, как мож
но манипулировать пустым элементом <img> на странице. Изначально
он выглядит следующим образом:
<img id="Image1" />
По умолчанию функция проверки корректности XHTML в Visual Stu
dio будет предупреждать об отсутствующих атрибутах, но мы будем
устанавливать обязательные атрибуты src и alt с помощью JavaScript.
Пример 14.3. Использование элемента управления ASP.NET AJAX – Image
ControlImage.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
<script language="JavaScript" type="text/javascript">
function pageLoad() {
var image = new Sys.Preview.UI.Image($get("Image1"));
image.set_imageURL("ajaxlogo.png");
image.set_alternateText("ASP.NET AJAX logo");
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<img id="Image1" />
290 Глава 14. Клиентские элементы управления
</div>
</form>
</body>
</html>
Результат работы примера показан на рис. 14.3. Для этого примера вам
необходимо загрузить изображение ajaxlogo.png (по адресу: http://
ajax.asp.net/images/ajaxposterphotologo.png) и поместить его в корне
вой каталог вебсервера. Файл с программным кодом примера вы най
дете на сайте книги (http://www.oreilly.com/catalog/9780596514242).
Гиперссылки
Ссылки на другие страницы и документы в HTML представляет эле
мент <a>, и он же используется в закладках. В ASP.NET AJAX гипер
ссылки представлены классом Sys.Preview.UI.HyperLink. Этот класс реа
лизует методы get_navigateURL() и set_navigateURL(), которые позволя
ют изменять адрес ссылки (только адрес URL, но не HTMLатрибут
target для адресации фрейма или окна). Он также предоставляет собы
тие click, для которого вы можете реализовать свой обработчик. (Обра
ботка событий будет описываться ниже, в этой же главе, в разделе
«Обработка событий в элементах управления».)
В примере 14.4 создается пустая ссылка (<a></a>), а адрес, на который
она ссылается, будет изменяться динамически. В примере ссылка ука
зывает на то же самое изображение логотипа ASP.NET AJAX, которое
использовалось в предыдущем примере.
Текст ссылки непосредственно через элемент управления Link изме
нить нельзя. Впрочем, ссылка не обязательно должна быть текстовой
ссылкой, она может содержать изображение или другой элемент. По
этому текст ссылки можно представить как другой элемент. Если вам
требуется изменять текст ссылки, вам нужно поместить внутрь ссыл
ки другой элемент (и задать для него ID).
Использование элементов управления ASP.NET AJAX 291
Кнопки
Язык разметки HTML поддерживает кнопки различных типов. На
пример: кнопка <input type="submit"> служит для отправки формы,
<input type="reset"> – для очистки формы (для перевода формы в перво
начальное состояние) и, наконец, кнопки <input type="button"> и <but
ton>, не имеющие предопределенного поведения и действие которых
можно определить с помощью JavaScript. В ASP.NET AJAX кнопки
реализованы в виде класса Sys.Preview.UI.Button. Этот класс поддержи
вает следующие методы:
get_argument()
Возвращает аргументы команды, которая была послана в результа
те щелчка на кнопке
set_argument()
Устанавливает аргументы кнопки
get_command()
Возвращает команду, которая была послана в результате щелчка на
кнопке
set_command()
Устанавливает команду кнопки
Всякий раз, когда вы устанавливаете значение свойства argument или
command, активируется встроенный механизм обработки событий (кото
рый будет описан ниже в этой же главе). Различные способы назначе
ния кнопкам функциональности можно найти в главе 16.
Флажки
Флажки в HTML определяются с помощью элемента <input type="check
box">. Флажок может иметь всего два состояния: установлен или сбро
шен. Эти состояния можно изменять из JavaScript, а значит, и ASP.NET
AJAX также обеспечивает подобную возможность. Метод set_checked()
позволяет изменить состояние флажка (получением логического значе
ния), а метод get_checked() возвращает текущее состояние. Соответ
ствующий класс в ASP.NET AJAX называется Sys.Preview.UI.CheckBox.
В примере 14.5 с помощью разметки HTML создается флажок, а с по
мощью ASP.NET AJAX/JavaScript производится изменение его со
стояния в значение true.
Пример 14.5. Использование элемента управления ASP.NET AJAX – CheckBox
ControlCheckBox.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
Использование элементов управления ASP.NET AJAX 293
<title>ASP.NET AJAX</title>
<script language="JavaScript" type="text/javascript">
function pageLoad() {
var checkbox = new Sys.Preview.UI.CheckBox($get("CheckBox1"));
checkbox.set_checked(true);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="checkbox" id="CheckBox1" />
<label for="CheckBox1">click me!</label>
</div>
</form>
</body>
</html>
Результат работы примера показан на рис. 14.5.
Списки выбора
В языке разметки HTML списки выбора (<select>...</select>) могут
иметь две формы представления: первая – раскрывающийся список,
который требует от пользователя произвести некоторое действие, чтобы
отобразить все элементы списка, и вторая – когда некоторые элементы
списка уже отображаются. Списки обоих типов в ASP.NET AJAX пред
ставлены одним классом Sys.Preview.UI.Selector. В отличие от Java
Script классы ASP.NET AJAX не предоставляют возможность изме
нять значения отдельных элементов списка.
294 Глава 14. Клиентские элементы управления
<title>ASP.NET AJAX</title>
<script language="JavaScript" type="text/javascript">
var label;
var select;
function pageLoad() {
label = new Sys.Preview.UI.Label($get("Label1"));
select = new Sys.Preview.UI.Selector($get("Select1"));
// Выполнять опрос каждую секунду, чтобы определить,
// какое значение было выбрано.
window.setInterval(
function() {
label.set_text(select.get_selectedValue());
},
1000);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<select id="Select1" size="3">
<option value="1">one</option>
<option value="2">two</option>
<option value="3">three</option>
</select><br />
Selected value: <label id="Label1"></label>
</div>
</form>
</body>
</html>
Результат работы примера показан на рис. 14.6.
var op = document.forms[0].elements["Select1"].options;
for (var i=0; i < op.length; i++) {
if (op[i].selected) {
// элемент выбран
} else {
// элемент не выбран
}
}
Текстовые поля
Однострочное текстовое поле в языке разметки HTML представлено те
гом <input type="text">. Управлять этим элементом можно с помощью
класса ASP.NET AJAX Sys.Preview.UI.TextBox. Платформа ASP.NET
AJAX поддерживает обработку событий от клавиатуры и, разумеется,
доступ на чтение и запись к текстовому содержимому элемента. По
следние две операции выполняются с помощью методов get_text()
и set_text().
Пример 14.7 читает данные, введенные в текстовое поле, с использова
нием той же методики циклического опроса, что и в предыдущем при
мере (setInterval()), и периодически копирует их из текстового поля
в элемент управления ASP.NET AJAX Label.
Пример 14.7. Использование элемента управления ASP.NET AJAX – TextBox
ControlTextBox.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
<script language="JavaScript" type="text/javascript">
function pageLoad() {
window.setInterval(
function() {
var label = new Sys.Preview.UI.Label($get("Label1"));
var textbox = new Sys.Preview.UI.TextBox($get("TextBox1"));
Использование элементов управления ASP.NET AJAX 297
label.set_text(textbox.get_text());
},
1000);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="TextBox1" /><br />
Entered value: <label id="Label1"></label>
</div>
</form>
</body>
</html>
Результат работы примера показан на рис. 14.7.
Базовые методы
Как уже обсуждалось выше, в разделе «Введение в клиентские элемен
ты управления ASP.NET AJAX», платформа ASP.NET AJAX поддер
298 Глава 14. Клиентские элементы управления
<style type="text/css">
.style1 { font family: Monospace; }
.style2 { border style: solid; }
.style3 { color: #00f; }
</style>
<script language="JavaScript" type="text/javascript">
function pageLoad() {
window.setInterval(
function() {
var label = new Sys.Preview.UI.Label($get("Label1"));
var rnd = Math.ceil(3 * Math.random());
label.toggleCssClass("style" + rnd);
label.set_text(label.get_element().className);
},
1000);
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
CSS class(es):
<label id="Label1">
</label>
</div>
</form>
</body>
</html>
Результат работы примера показан на рис. 14.8.
Подведение итогов
В данной главе было показано, что предлагается платформой ASP.NET
AJAX в пространстве имен Sys.Preview.UI на стороне клиента – в част
ности, специфичный для ASP.NET AJAX способ работы с HTMLэле
ментами из программного кода JavaScript. Кроме того, здесь описыва
ется возможность обработки событий средствами ASP.NET AJAX.
В следующей главе будет показано, как выполняется привязка дан
ных к клиентским элементам, чтобы избежать необходимости выпол
нять присваивание значений вручную. Механизм привязки данных
также позволяет выполнять синхронизацию элементов – то есть свя
зывать элементы между собой так, что изменения в одном элементе от
ражаются в другом и наоборот.
Привязка данных
Механизм привязки данных связывает данные с HTMLэлементами,
которые обеспечивают визуальное представление этих данных.
В ASP.NET привязка данных используется с такими элементами
управления, как GridView, FormView и DetailsView. При этом, разумеется,
имеется возможность привязывать данные и к другим объектам, та
ким как маркированные списки.
306 Глава 15. Привязка и проверка данных
Sys.Preview.BindingBase.Transformers.Invert
Преобразует значение true в false, а false в true
Sys.Preview.BindingBase.Transformers.ToString
Преобразует значение в строку аналогично методу String.Format();
допускается использование символовзаполнителей
Sys.Preview.BindingBase.Transformers.Adds
Добавляет к исходному значению некоторое другое значение
Sys.Preview.BindingBase.Transformers.Multiply
Умножает исходное значение на некоторое другое значение
Sys.Preview.BindingBase.Transformers.Compare
Сравнивает исходное значение с заданным и возвращает true в слу
чае их равенства и false – в противном случае
Sys.Preview.BindingBase.Transformers.CompareInverted
Сравнивает исходное значение с заданным и возвращает false в слу
чае их равенства и true – в противном случае
Некоторые из этих преобразователей принимают аргумент, значение
которого может быть установлено с помощью метода set_transformerAr
gument() (например, строка формата для преобразователя ToString).
Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
Полный программный код приводится в примере 15.1. При вводе текста
в поле ничего происходить не будет. Но когда вы покинете поле ввода
либо с помощью клавиши табуляции, либо щелчком мыши за предела
ми поля, произойдет событие propertyChanged, отработает механизм при
вязки и введенный текст появится в метке, как показано на рис. 15.1.
Пример 15.1. Использование механизма привязки данных ASP.NET AJAX
с преобразователем
ControlBindingTextBox.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<script language="JavaScript" type="text/javascript">
function pageLoad() {
var textbox = new Sys.Preview.UI.TextBox($get("TextBox1"));
var label = new Sys.Preview.UI.Label($get("Label1"));
var binding = new Sys.Preview.Binding();
binding.set_dataContext(textbox);
binding.set_dataPath("text");
binding.set_property("text");
binding.add_transform(Sys.Preview.BindingBase.Transformers.ToString);
binding.set_transformerArgument("Text entered: {0}");
binding.set_target(label);
textbox.initialize();
label.initialize();
binding.initialize();
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="TextBox1" /><br />
<label id="Label1"></label>
</div>
</form>
</body>
</html>
Направление привязки
По умолчанию привязка является «входящей», то есть данные копи
руются из источника в приемник. Представьте, что вы заменили эле
мент Label другим текстовым полем и настроили привязку, как и пре
жде. В таком случае данные будут копироваться из первого текстового
поля во второе, но не наоборот. Такое поведение можно изменить, вы
звав метод set_direction() объекта Binding. Допустимыми значениями
аргумента этого метода являются следующие:
Sys.Preview.BindingDirection.In
Данные копируются из источника в приемник (значение по умолча
нию)
Sys.Preview.BindingDirection.Out
Данные копируются из приемника в источник. Это особенно удобно
при создании обратного эффекта в некоторых преобразователях
Sys.Preview.BindingDirection.InOut
При изменении значения свойства источника или приемника дан
ные копируются в другой элемент управления
Следующий фрагмент создаст двунаправленную привязку:
binding.set_direction(Sys.Preview.BindingDirection.InOut);
Направление привязки имеет важное значение при использовании
преобразователей Add или Multiply. Если используется направление
привязки Sys.Preview.BindingDirection.InOut, ASP.NET AJAX будет вы
полнять преобразование в обратном направлении, интерпретируя пре
образователь Add как операцию вычитания, а Multiply – деления.
Привязка данных 311
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="TextBox1" /><br />
<label id="Label1"></label>
</div>
</form>
</body>
</html>
Использование разметки
для привязки данных: xmlscript
Программный подход к привязке данных прекрасно работает, но дек
ларативный способ также имеет свои преимущества. Например, при
декларативном подходе проблемы с вызовом метода initialize() (о ко
торой говорилось в предыдущем разделе) просто не существует.
В предварительные версии ASP.NET AJAX компания Microsoft ввела
xmlscript – формат разметки специально для добавления функцио
нальных возможностей в страницы ASP.NET AJAX. Группа разработ
чиков ASP.NET AJAX предполагала, что использование встроенной
разметки XML прекрасно подойдет для представления дополнительной
информации, которая сможет быть интерпретирована JavaScript во
время исполнения на стороне клиента. Кроме того, такой подход дает
разработчикам стандартную разметку, которая легко читается и даже
может поддерживаться инструментальными средствами. Недостаток –
отсутствие поддержки разметки xmlscript механизмом IntelliSense
в Visual Studio. (Дополнительную информацию об этом решении вы
найдете в блоге http://www.nikhilk.net/AtlasXMLScript.aspx.) В какой
то момент компания Microsoft решила не продолжать дальнейшую ра
боту над xmlscript. Эта особенность попрежнему присутствует в паке
те Futures (и потому будет описана в этом разделе), но надежды на то,
что она попадет в ядро ASP.NET AJAX Extensions, минимальны.
Основная схема xmlscript выглядит примерно так:
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components />
</page>
</script>
314 Глава 15. Привязка и проверка данных
Привязка данных
Привязка данных выполняется с помощью элемента <binding>. Этот
элемент должен объявляться как дочерний для связываемого элемен
Привязка данных 315
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="TextBox1" /><br />
<label id="Label1"></label>
</div>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<textBox id="TextBox1" />
<label id="Label1">
<bindings>
<binding dataContext="TextBox1"
dataPath="text"
property="text"
transform="ToString"
transformerArgument="Text entered: {0}" />
</bindings>
</label>
</components>
</page>
</script>
</body>
</html>
Обработка событий
В главе 14 рассматривалась обработка событий в клиентских элемен
тах управления ASP.NET AJAX. С помощью xmlscript можно настро
ить обработку событий полностью декларативным способом.
Как и в случае с привязкой данных, все необходимое должно объяв
ляться в разделе <components> блока xmlscript. Каждый элемент собы
тия (например, click) поддерживает следующие три дочерних элемента:
<setPropertyAction>
Определяет свойства элемента
<invokeMethodAction>
Вызов метода
<button click="someFunction">
Декларативно добавляет обработчик события
Привязка данных 317
Вызов методов
Возможность изменять значение свойства – это удобно, но обязательно
должна присутствовать и возможность вызывать методы при появле
нии событий. Как и следовало ожидать, такая возможность также
обеспечивается с помощью xmlscript. Для этого необходимо опреде
лить два элемента:
• Элемент <invokeMethodAction>
• Элемент <parameters>
Элемент <invokeMethodAction> поддерживает следующие атрибуты:
method
Определяет имя вызываемого метода
target
Определяет имя объекта, которому принадлежит вызываемый метод
В данном случае вы не ограничены встроенными функциональными
возможностями. Например, можно использовать определение <invoke
MethodAction> для обращения к методу вебслужбы. Попробуем создать
простую вебслужбу, которая будет возвращать два значения: style1
или style2. Программный код вебслужбы приводится в примере 15.5.
Пример 15.5. Вебслужба, случайным образом возвращающая имя класса CSS
RandomCssClass.asmx
<%@ WebService Language="C#" Class="RandomCssClass" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class RandomCssClass : System.Web.Services.WebService {
[WebMethod]
public string getRandomCssClass() {
Random r = new Random();
return "style" + r.Next(1, 3);
}
}
Далее мы будем использовать эту вебслужбу для форматирования
элемента в соответствии с классом CSS, получаемым от вебслужбы.
Ниже приводится определение двух классов CSS:
<style type="text/css">
.style1 { font family: Monospace; border style: dotted; color: #0f0; }
.style2 { font family: Sans Serif; border style: solid; color: #0ff; }
</style>
320 Глава 15. Привязка и проверка данных
property="value" />
</bindings>
</setPropertyAction>
</completed>
</serviceMethodRequest>
Наконец, необходимо реализовать вызов метода по щелчку на кнопке.
По умолчанию для передачи дополнительных данных при обращении
к вебслужбам поддерживается свойство userContext (глава 5). Все па
раметры определяются внутри элемента <parameters> в виде атрибутов,
поэтому передать один или более параметров будет очень просто. Эти
атрибуты определяются как пары parametername=parametervalue, вслед
ствие чего отпадает необходимость использовать подэлементы.
Разметка, показанная в следующем фрагменте, вызывает метод веб
службы и передает ему пустой пользовательский контекст (это значение
по умолчанию, поэтому атрибут userContext можно было бы опустить).
<button id="Button1">
<click>
<invokeMethodAction target="randomCssMethod" method="invoke">
<parameters userContext="" />
</invokeMethodAction>
</click>
</button>
Нам пришлось приложить немало усилий, а кроме того, такой подход
увеличивает вероятность появления ошибок. Например, обнаружение
синтаксических ошибок в разметке xmlscript окажется нелегким
делом, – сценарий просто не будет работать, но кроме этого вы не полу
чите никаких подсказок. Поэтому вам следует рассмотреть возмож
ность использования средств проверки разметки XML для проверки
кода xmlscript. В примере 15.6 приводится полный код страницы, а
на рис. 15.4 – результат ее отображения в броузере.
Пример 15.6. Вызов методов вебслужб и привязка данных
с использованием xmlscript
ControlDeclarativeMethod.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<style type="text/css">
.style1 { font family: Monospace; border style: dotted; color: #0f0; }
.style2 { font family: Sans Serif; border style: solid; color: #0ff; }
</style>
</head>
<body>
<form id="form1" runat="server">
322 Глава 15. Привязка и проверка данных
Рис. 15.4. Щелчок на кнопке вызывает случайное изменение класса CSS метки
Проверка данных 323
</setPropertyAction>
</completed>
</serviceMethodRequest>
</components>
</page>
</script>
</body>
</html>
Проверка данных
В дополнение к элементам управления, реализующим механизм при
вязки данных, в пакете ASP.NET AJAX Futures содержатся свои соб
ственные клиентские элементы управления, предназначенные для вы
полнения проверки данных, введенных пользователем, – особенность,
которую многие разработчики на ASP.NET считают весьма полезной.
Платформа ASP.NET AJAX поддерживает следующие валидаторы:
requiredFieldValidator
Проверяет, было ли чтото введено пользователем в элемент управ
ления
regexValidator
Проверяет данные в элементе управления на соответствие регуляр
ному выражению
typeValidator
Проверяет, соответствуют ли данные в элементе управления тре
буемому типу данных
rangeValidator
Проверяет данные в элементе управления на соответствие заданно
му диапазону значений
customValidator
Проверяет данные в элементе управления с использованием нестан
дартной функции
id
Идентификатор элемента управления, отображающего сообщения
об ошибках
associatedControl
Идентификатор проверяемого элемента
Полный код страницы приводится в примере 15.7.
Пример 15.7. Использование валидатора для проверки полей, обязательных
к заполнению
ControlValidationRequiredField.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="TextBox1" />
<span id="Error1" style="color: red;">*</span>
<br />
<input type="submit" />
</div>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<textBox id="TextBox1">
<validators>
<requiredFieldValidator
errorMessage="** TextBox1 value missing" />
</validators>
</textBox>
<validationErrorLabel id="Error1" associatedControl="TextBox1" />
</components>
</page>
</script>
</body>
</html>
326 Глава 15. Привязка и проверка данных
</script>
</body>
</html>
Собственные валидаторы
Для достижения большей гибкости приложения поддерживается воз
можность создания своих собственных валидаторов для проверки
пользовательских данных. Сигнатура функциивалидатора имеет сле
дующий вид:
function <name>(sender, args) {}
Первый аргумент функции – это элемент, вызвавший операцию про
верки, но более важное значение имеет второй аргумент, где передается
значение для проверки, доступ к которому можно получить с помощью
метода get_value(). После проверки необходимо вызвать метод set_is
Value(), которому в случае успеха передается значение true, а в случае
неудачи – значение false.
Исключительно в демонстрационных целях рассмотрим случай, когда
по некоторым причинам в текстовое поле допускается вводить только
квадраты целых чисел. Данную проверку выполняет следующая
функция:
function validateSquare(sender, args) {
var value = args.get_value();
args.set_isValid(Math.sqrt(value) == Math.floor(Math.sqrt(value)));
}
В xmlscript элемент <customValidator> должен содержать атрибут vali
dateValue, который будет ссылаться на функциювалидатор:
<customValidator validateValue="validateSquare"
errormessage="** square numbers only" />
В примере 15.11 приводится полный программный код этой нестан
дартной функциивалидатора.
Пример 15.11. Использование собственного валидатора
ControlValidationCustom.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<script type="text/javascript">
function validateSquare(sender, args) {
var value = args.get_value();
args.set_isValid(Math.sqrt(value) == Math.floor(Math.sqrt(value)));
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="TextBox1" />
<span id="Error1" style="color: red;">*</span>
<br />
<input type="submit" />
</div>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<textBox id="TextBox1">
<validators>
<requiredFieldValidator
errorMessage="** TextBox1 value missing" />
<typeValidator type="Number" errorMessage="** numbers only" />
<customValidator validateValue="validateSquare"
errorMessage="** square numbers only" />
</validators>
</textBox>
<validationErrorLabel id="Error1" associatedControl="TextBox1" />
</components>
332 Глава 15. Привязка и проверка данных
</page>
</script>
</body>
</html>
Программная проверка
Декларативный подход прекрасно зарекомендовал себя на практике,
однако существует и программный подход к проверке данных (кото
рый добавляет проверку во время исполнения).
Впрочем, и при таком подходе попрежнему требуется выполнить не
которые объявления, такие как показаны в следующем фрагменте:
<textBox id="TextBox1">
</textBox>
<validationErrorLabel id="Error1"
associatedControl="TextBox1" />
Валидатор можно создать с помощью программного кода JavaScript.
Для этого необходимо пройти два этапа:
1. Добавить валидатор: element.get_validators().add(validator).
2. Если вы предполагаете использовать функцию обратного вызова
(которая вызывается, когда возникает потребность в выполнении
проверки), используется синтаксис: element.add_validated(function).
Невозможно сделать доступным для проверки элемент с помощью
обычной операции new Sys.Preview.UI.XXX. Вместо этого необходимо ис
пользовать несколько непривычный синтаксис, который будет пред
ставлен в ходе обсуждения реализации предотвращения отправки
формы:
var textbox = $get("TextBox1").control;
Сначала мы отыскиваем элемент управления (на стороне клиента)
с помощью функции $get(), а затем получаем ссылку на него с помо
щью свойства control. В примере 15.12 приводится полный код стра
ницы, использующей программный подход к реализации проверки.
В этом примере выполняется проверка обязательного к заполнению
поля, которая приводилась в примере 15.7, но на этот раз валидатор
добавляется к текстовому полю из программного кода JavaScript.
Пример 15.12. Программный подход к построению собственного валидатора
ControlValidationCustomProgrammatic.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
Проверка данных 333
<script type="text/javascript">
function pageLoad() {
var textbox = $get("TextBox1").control;
validator = new Sys.Preview.UI.RequiredFieldValidator();
validator.set_errorMessage("** enter some data");
textbox.get_validators().add(validator);
textbox.add_validated(validationComplete);
}
function validationComplete(sender, args) {
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="TextBox1" />
<span id="Error1" style="color: red;">*</span>
<br />
<input type="submit" />
</div>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<textBox id="TextBox1">
</textBox>
<validationErrorLabel id="Error1"
associatedControl="TextBox1" />
</components>
</page>
</script>
</body>
</html>
Этот подход можно использовать и для реализации более сложных ва
лидаторов, включая свои собственные валидаторы. Синтаксис объяв
ления собственной функциивалидатора имеет следующий вид:
validator.add_validateValue(validation function);
В примере 15.13 демонстрируется, как можно добавлять валидаторы
к полю ввода декларативным и программным способами. Валидаторы,
проверяющие наличие данных в поле и тип данных, добавляются дек
ларативно, а авторский валидатор – программно. Результат получает
ся тот же самый, что и в предыдущих примерах.
334 Глава 15. Привязка и проверка данных
</validators>
</textBox>
<validationErrorLabel id="Error1"
associatedControl="TextBox1" />
</components>
</page>
</script>
</body>
</html>
Групповая проверка
Элементы проверки могут быть сгруппированы вместе, что позволяет
выполнять проверку нескольких элементов управления как единого
целого. Группы проверяемых компонентов создаются с помощью эле
мента <validationGroup>. Каждый валидатор в группе выполняет свою
проверку независимо от других, но вся группа проходит тестирование
как один объект. Если какаято из проверок в группе терпит неудачу,
то неудачу терпит и вся группа. Естественно, с другой стороны, что ес
ли все проверки в группе выполнены успешно, то и вся группа счита
ется успешно прошедшей проверку. Группировка особенно полезна,
когда по некоторому условию бывает необходимо активировать и деак
тивировать отдельные наборы валидаторов. В следующем примере де
монстрируется, как можно управлять видимостью элементов в случае
успешного выполнения проверок во всех условных валидаторах.
Группа проверки имеет метод isValid(), который определяет успех или
провал проверки. Он может использоваться в соединении с механизмом
привязки данных для отображения сообщения, текст которого зависит
от успешного или неудачного прохождения всех проверок в группе.
Прежде всего, необходимо создать элемент для отображения сообще
ния:
<div id="Errors"> no errors </div>
Затем нужно связать свойство visible этого элемента с методом группы
isValid(). Если все валидаторы в группе успешно выполняют провер
ку, элемент <div> становится видимым.
<label id="Errors">
<bindings>
<binding dataContext="group" dataPath="isValid" property="visible" />
</bindings>
</label>
Чтобы сделать элемент <div> видимым в случае неудачной проверки,
используется преобразователь Invert:
<binding dataContext="group" dataPath="isValid" property="visible"
transform="Invert" />
336 Глава 15. Привязка и проверка данных
Рис. 15.6. Метка становится видимой, только если все поля ввода были
заполнены без ошибок
338 Глава 15. Привязка и проверка данных
</validationGroup>
<label id="Errors">
<bindings>
<binding dataContext="group" dataPath="isValid"
property="visible" />
</bindings>
</label>
</components>
</page>
</script>
</body>
</html>
Подведение итогов
В этой главе мы познакомились с механизмом привязки данных и эле
ментами проверки правильности данных, которые входят в состав па
кета ASP.NET AJAX Futures. В сравнении с элементами проверки
в ASP.NET они испытывают определенный недостаток функциональ
ных возможностей. Кроме того, использование элементов управления
ASP.NET AJAX выглядит немного необычно по сравнению с их сервер
ными аналогами. Они не интегрированы в механизм отправки форм
броузера, а это означает, что пользователь имеет возможность отпра
вить форму, даже если в ней присутствуют ошибочные данные. И нако
нец, последнее и самое важное – элементы проверки ASP.NET AJAX
работают только на стороне клиента и только при наличии поддержки
JavaScript. Элементы проверки ASP.NET работают как на стороне
клиента, так и на стороне сервера, и потому проверку, построенную на
их основе, нельзя обойти, просто отключив поддержку JavaScript. Это
делает их использование более предпочтительным, если у вас есть воз
можность выбирать. Однако следует отметить, что если вебсайт ис
пользует платформу ASP.NET AJAX для организации всех эффектов
на стороне клиента, то валидаторы ASP.NET AJAX прекрасно интег
рируются с другими особенностями ASP.NET AJAX.
<behaviors>
<clickBehavior>
<click>
<setPropertyAction target="Panel1"
property="visible" value="true" />
<setPropertyAction target="Panel2"
property="visible" value="false" />
</click>
</clickBehavior>
</behaviors>
</label>
<label id="Show2">
<behaviors>
<clickBehavior>
<click>
<setPropertyAction target="Panel1"
property="visible" value="false" />
<setPropertyAction target="Panel2"
property="visible" value="true" />
</click>
</clickBehavior>
</behaviors>
</label>
</components>
</page>
</script>
</body>
</html>
На рис. 16.1 показана страница, созданная разметкой из примера 16.1.
шем случае вся панель будет исполнять роль такой рукоятки, поэтому
используем ее идентификатор.
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<control id="DragPanel">
<behaviors>
<floatingBehavior handle="DragPanel" />
</behaviors>
</control>
</components>
</page>
</script>
Полный программный код страницы приводится в примере 16.2.
Пример 16.2. Добавление аспекта поведения «перетащитьиотпустить»
к панели
DragDrop.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
inbox.Text = new Random().Next(0, 100).ToString( );
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<style type="text/css">
.box { border: solid 2px black; }
.mailbox { border: solid 2px black; width: 150px; }
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference name="PreviewScript.js"
assembly="Microsoft.Web.Preview" />
<asp:ScriptReference name="PreviewDragDrop.js"
assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<asp:Panel ID="ContentPanel" CssClass="box" runat="server">
<h1>My Portal</h1>
348 Глава 16. Использование клиентских аспектов поведения и компонентов
<p>
Welcome to your personal portal, powered by Microsoft ASP.NET AJAX.
The mail status window is freely draggable. Welcome to your personal
portal, powered by ASP.NET AJAX.
The mail status window is freely draggable. Welcome to your personal
portal, powered by ASP.NET AJAX.
The mail status window is freely draggable.
</p>
[...]
</asp:Panel>
<asp:Panel CssClass="mailbox" ID="DragPanel" runat="server">
<p>
You currently have <asp:Label id="inbox" runat="server"></asp:Label>
mails in your <a href="http://www.hotmail.com/">inbox</a>.
</p>
</asp:Panel>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<control id="DragPanel">
<behaviors>
<floatingBehavior handle="DragPanel" />
</behaviors>
</control>
</components>
</page>
</script>
</body>
</html>
Запустите пример и посмотрите, как выглядит страница в окне броузе
ра. Вы можете отбуксировать прямоугольник в любое место внутри по
родившей его страницы и оставить его там (но вы не можете, напри
мер, отбуксировать панель в нижнюю часть окна, расположенную за
пределами HTMLразметки страницы). На рис. 16.2 видно, что сквозь
перемещаемую панель в процессе буксировки видна лежащая ниже
панель с текстом. Следует отметить, что панель вернется на свое пер
воначальное место при обновлении страницы. Далее в этой главе вы
узнаете, как сохранять положение панели между сеансами броузера.
Индивидуализация поведения
«перетащитьиотпустить»
В предыдущих примерах имеется одно ограничение. Как уже было
продемонстрировано, наша панель может свободно перемещаться по
всей поверхности страницы. Однако если покинуть страницу и вер
Использование аспектов поведения 351
чтения» в конце этой главы, кроме того, обзор этих возможностей при
водится в главе 7). Платформа ASP.NET AJAX поддерживает свойства
профиля для некоторых из своих элементов управления, включая и
DragDropExtender. Положение перемещаемой панели можно сохранить
в свойстве ProfileProperty компонента DragOverlayExtender.
Чтобы иметь возможность сохранять данные о положении, нужно соз
дать свойство профиля в файле Web.config в виде следующей разметки:
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.web>
<anonymousIdentification enabled="true" />
<profile>
<properties>
<add name="DragPanelPosition" allowAnonymous="true" />
</properties>
</profile>
[...]
</system.web>
<system.web.extensions>
<scripting>
<webServices>
<profileService enabled="true"
writeAccessProperties="DragPanelPosition"
readAccessProperties="DragPanelPosition" />
[...]
</webServices>
</scripting>
</system.web.extensions>
</configuration>
Использование компонентов
Компоненты ASP.NET AJAX инкапсулируют самостоятельный про
граммный код JavaScript, который не привязан к конкретным HTML
элементам страницы. Каждый компонент ASP.NET AJAX содержит
ряд функциональных возможностей JavaScript для обеспечения ис
пользования в сценариях единого интерфейса. В отличие от аспекта
поведения, который непременно должен быть привязан к конкретному
элементу страницы, компонент может предложить более широкие
функциональные возможности. В состав пакета Futures входит не
сколько компонентов, большинство из которых предназначены для ра
боты с данными (в чем вы убедитесь в главе 17), но здесь мы рассмот
рим только один компонент, обладающий большой практической цен
ностью: компонент таймера. Это эквивалент для xmlscript серверного
элемента управления Timer, демонстрировавшегося в главе 6. Он обес
печивает аналогичную функциональность, но не имеет официальной
поддержки Microsoft, так же как и xmlscript, и сам пакет Futures.
</div>
<div id="Panel2" style="visibility: hidden; position: absolute;
top: 35px; left: 10px">
This is the second tab.<br />
It is full of ASP.NET AJAX information, as well.<br />
Although it seems to be full of dummy text, too.
</div>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<control id="Panel1" />
<control id="Panel2" />
<timer id="Timer1" interval="5000" enabled="true">
<tick>
<setPropertyAction target="Panel1" property="visible"
value="true" />
<setPropertyAction target="Panel2" property="visible"
value="false" />
</tick>
</timer>
</components>
</page>
</script>
</body>
</html>
Подведение итогов
В этой главе рассматривались аспекты поведения, такие как щелчок
и «перетащитьиотпустить». Здесь также было дано введение в ком
поненты ASP.NET AJAX, на которые, как было показано, можно со
слаться с помощью xmlscript. Хотя сами компоненты реализованы на
JavaScript, тем не менее xmlscript предоставляет возможность декла
ративного добавления функциональности к элементам управления
и вебсайтам.
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
public class Vendor
{
string _AccountNumber;
string _Name;
public string AccountNumber
{
get
{
return _AccountNumber;
}
set
{
_AccountNumber = value;
}
}
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
public Vendor(string AccountNumber, string Name)
{
this._AccountNumber = AccountNumber;
this._Name = Name;
}
public Vendor( )
{
}
}
[WebService(Namespace = "http://hauser wenz.de/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class Vendors : System.Web.Services.WebService
{
[WebMethod]
Использование элемента управления ListView 367
...
</template>
</itemTemplate>
</listView>
Внутри элемента <template> следует определить привязку данных к ка
ждому элементу списка. Поскольку в этом примере будет выводиться
текст, можно использовать элемент <label>, который имеет свое пред
ставление в ASP.NET AJAX в виде элемента управления Label. В коде
разметки нужно определить значения следующих двух свойств:
dataPath
Имя свойства класса, которое будет служить источником данных
property
Свойство элемента управления Label, куда должны записываться
данные
В результате мы приходим к следующей разметке:
<listView itemTemplateParentElementId="vendorsItemParent" id="output">
<layoutTemplate>
<template layoutElement="vendorsLayout" />
</layoutTemplate>
<itemTemplate>
<template layoutElement="vendorsItem">
<label id="vendorsName">
<bindings>
<binding dataPath="Name" property="text" />
</bindings>
</label>
</template>
</itemTemplate>
</listView>
Это немалый труд, причем все придется делать без поддержки меха
низма IntelliSense. Но результат стоит того. Заключительный шаг со
стоит в том, чтобы загрузить библиотеку JavaScript – PreviewScript.js
из пакета Futures, которая содержит фактическую клиентскую функ
циональность:
<asp:ScriptManager runat="server">
<Services>
<asp:ServiceReference Path="ListViewVendors.asmx" />
</Services>
<Scripts>
<asp:ScriptReference Name="PreviewScript.js"
Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
В примере 17.3 приводится полный код разметки и сценариев для этой
страницы.
Использование элемента управления ListView 371
<layoutTemplate>
<template layoutElement="vendorsLayout" />
</layoutTemplate>
<itemTemplate>
<template layoutElement="vendorsItem">
<label id="vendorsName">
<bindings>
<binding dataPath="Name" property="text" />
</bindings>
</label>
</template>
</itemTemplate>
</listView>
</components>
</page>
</script>
</body>
</html>
На рис. 17.1 показано содержимое страницы после щелчка на кнопке
Load Vendors (загрузить список производителей).
Далее коротко описывается, что происходит в действительности:
1. Когда производится щелчок на кнопке, вызывается вебслужба.
2. Как только вебслужба вернет данные, исполняется функция обрат
ного вызова.
3. Программный код JavaScript в цикле обходит набор данных, полу
ченный от вебслужбы.
</div>
</form>
<script type="text/xml script">
<page xmlns="http://schemas.microsoft.com/xml script/2005">
<components>
<listView itemTemplateParentElementId="vendorsItemParent" id="output">
<layoutTemplate>
<template layoutElement="vendorsLayout" />
</layoutTemplate>
<itemTemplate>
<template layoutElement="vendorsItem">
<label id="vendorsAccountNumber">
<bindings>
<binding dataPath="AccountNumber" property="text" />
</bindings>
</label>
<label id="vendorsName">
<bindings>
<binding dataPath="Name" property="text" />
</bindings>
</label>
</template>
</itemTemplate>
</listView>
</components>
</page>
</script>
</body>
</html>
Результат работы страницы показан на рис. 17.2.
{
v.Add(new Vendor(
dr["AccountNumber"].ToString( ),
dr["Name"].ToString( )));
}
return v.ToArray( );
}
Как вариант, можно возвращать тип DataTable, для чего требуется
меньше программного кода, как показано в примере 17.6. Выбор этого
типа возвращаемого значения требует, чтобы метод возвращал Data
Table, а не DataRowCollection!
Пример 17.6. Метод, возвращающий DataTable
ListViewVendorsDataService.asmx
<%@ WebService Language="C#" Class="VendorsDataService" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Data;
using System.Data.SqlClient;
using Microsoft.Web.Preview.Services;using System.ComponentModel;
[WebService(Namespace = "http://hauser wenz.de/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class VendorsDataService : DataService
{[DataObjectMethod(DataObjectMethodType.Select)]
public DataTable GetVendors( )
{
SqlConnection conn = new SqlConnection(
"server=(local)\\SQLEXPRESS; Integrated Security=true;
InitialCatalog=AdventureWorks");
conn.Open( );
SqlCommand comm = new SqlCommand(
"SELECT TOP 10 AccountNumber, Name FROM Purchasing.Vendor",
conn);
SqlDataAdapter adap = new SqlDataAdapter(comm);
DataSet ds = new DataSet( );
adap.Fill(ds);
return ds.Tables[0];
}
}
Эти файлы не содержат методов, явно помеченных атрибутом [Web
Method]. Однако если обратиться к одной из этих вебслужб непосред
ственно из броузера, можно увидеть, что они имеют два метода: Get
Data() и SaveData() (рис. 17.3). Оба метода ожидают получить массив pa
rameters с дополнительной информацией. Платформа ASP.NET AJAX
автоматически генерирует обязательные параметры, поэтому вы про
Создание собственного источника данных 379
</table>
</div>
</div>
Однако в xmlscript необходимо внести некоторые изменения по срав
нению с предыдущим примером. Начинается все как обычно:
<script type="text/xml script">
<page xmlns="http://schemas.microsoft.com/xml script/2005">
<components>
...
</components>
</page>
</script>
Затем следует указать ссылку на источник данных. Поскольку это не
обычная вебслужба, объект ScriptManager не может использоваться
для ссылки на эту вебслужбу. Вместо него следует использовать эле
мент <dataSource>. В этом элементе необходимо определить значения
URL и идентификатора – идентификатор нам потребуется позже!
<script type="text/xml script">
<page xmlns="http://schemas.microsoft.com/xml script/2005">
<components>
<dataSource id="vendorSource"
serviceURL="ListViewVendorsDataService.asmx" />
...
</components>
</page>
</script>
Теперь настало время элемента управления ListView и его расширения –
элемента <listView>. Самый важный шаг – это привязка источника
данных из предыдущего фрагмента кода к элементу управления List
View. В свойства dataPath и property должно быть записано значение data,
а свойство dataContext должно ссылаться на идентификатор элемента
<dataSource>:
<listView id="vendorsList" itemTemplateParentElementId="vendorsItemParent"
targetElement="output">
<bindings>
<binding dataContext="vendorSource" dataPath="data" property="data" />
</bindings>
...
</listView>
Элементы <layoutTemplate> и <itemTemplate> остались без изменений,
привязка данных выполняется к элементу <table> и вложенным в него
подэлементам.
Однако мы упустили одну вещь. Данные мы привязали, но еще не за
грузили. Источник данных поддерживает свойство с именем autoLoad.
Если этому свойству присвоить значение true, метод Select источника
данных будет вызван автоматически.
Создание собственного источника данных 381
</bindings>
<layoutTemplate>
<template layoutElement="vendorsLayout" />
</layoutTemplate>
<itemTemplate>
<template layoutElement="vendorsItem">
<label id="vendorsAccountNumber">
<bindings>
<binding dataPath="AccountNumber" property="text" />
</bindings>
</label>
<label id="vendorsName">
<bindings>
<binding dataPath="Name" property="text" />
</bindings>
</label>
</template>
</itemTemplate>
</listView>
</components>
</page>
</script>
</body>
</html>
Нам удалось избежать необходимости писать программный код (исклю
чение составляет класс DataService вебслужбы) и обойтись одними дек
ларациями. Этот пример выводит первые 10 записей из таблицы Pur
chasing.Vendors в виде HTMLэлемента <table>. Таким образом, резуль
тат работы этого сценария идентичен тому, что приводится на рис. 17.2.
Управление данными
Отображение данных – это лишь первый шаг. Далее вполне ло
гично было бы реализовать остальные методы, определяемые
в перечислении System.ComponentModel.DataObjectMethodType. После
этого можно было бы листать данные, изменять их и многое дру
гое. Это порождает целый набор новых возможностей. Достичь
более высокой производительности приложения и эффективно
сти процесса разработки можно было бы при использовании эле
мента управления ASP.NET – GridView (или любого другого под
ходящего элемента управления для работы с данными). Если вас
волнует проблема полного обновления страницы, которая при
суща элементу управления GridView, вернитесь к главе 6, где был
представлен способ преодоления этого ограничения – разумеет
ся, с использованием возможностей ASP.NET AJAX.
Подведение итогов 383
Подведение итогов
В этой главе рассказывалось о том, как организовать со стороны кли
ента доступ к данным, расположенным на сервере. Для отображения
информации, находящейся на сервере, мы реализовали вебслужбу,
а затем воспользовались механизмом привязки данных ASP.NET
AJAX и специальными клиентскими элементами управления, такими
как ListView.
MyDomain.tld AnotherDomain.tld
(2) Вызов вебметода
Сервер (.asbx) Вебслужбы
(3) Возвращаемые данные
(1) Вызов (4) Возвращаемые
объекта данные
посредника
(Call bridge)
Клиент (.aspx)
query,
0, // смещение первого результата
10, // максимальное число результатов
false, // следует ли отбрасывать похожие результаты
"", // набор условий Google, ограничивающих поиск
false, // следует ли отбрасывать содержимое,
// предназначенное только для совершеннолетних
"", // ограничение поиска по языку
"", // игнорируется, так же как и следующий параметр
"");
}
}
Теперь можно использовать полученный мост к вебслужбе. Для акти
вации моста к вебслужбе следует предоставить всю необходимую ин
формацию о вебслужбе в виде файла .asbx. Создайте в корневом ката
логе вашего вебсайта XMLфайл с именем Google.asbx.
Добавьте в файл .asbx пространство имен, где будет размещаться мост
к вебслужбе (атрибут namespace) и имя класса реализации моста (атри
бут className).
<bridge namespace="OReilly.AspNetAJAX" className="Google" >
В элементе <proxy> должно быть указано имя классаобертки и ката
лог, где его можно будет найти:
<proxy type="GoogleSearchServiceWrapper, App_Code" />
Затем необходимо перечислить все методы вебслужбы, включая име
на аргументов. Все аргументы, перечисленные здесь, позднее смогут
использоваться в сценариях JavaScript. Не забудьте, что ключ лицен
зии хранится в файле Web.config. Из этого следует, что значение аргу
мента, в котором передается ключ лицензии, не может быть установ
лено из JavaScript. Вместо этого мы можем загружать ключ из раздела
<appSettings> во время исполнения, используя следующий синтаксис:
<parameter name="licenseKey" value="% appsettings : GoogleLicenseKey %"
serverOnly="true" />
Атрибут serverOnly="true" обеспечивает недоступность аргумента li
censeKey для программного кода JavaScript, поэтому значение ключа
всегда будет извлекаться из файла Web.config.
На этом все. Полный программный код из файла моста приводится
в примере 18.2.
Пример 18.2. Реализация моста к вебслужбе Google
Google.asbx
<?xml version="1.0" encoding="utf 8" ?>
<bridge namespace="OReilly.AspNetAJAX" className="Google" >
<proxy type="GoogleSearchServiceWrapper, App_Code" />
<method name="Search">
390 Глава 18. Использование внешних веб"служб
<input>
<parameter name="licenseKey"
value="% appsettings : GoogleLicenseKey %"
serverOnly="true" />
<parameter name="query" />
</input>
</method>
</bridge>
Теперь все, что осталось сделать, это написать страницу .aspx, исполь
зующую мощь платформы ASP.NET AJAX. На странице нам потребу
ются текстовое поле, куда будет вводиться поисковый запрос, кнопка,
запускающая поиск, и некоторые заполнители, где будут отображать
ся результаты поиска.
Разметка может выглядеть примерно так:
<div>
<input type="text" id="Query" />
<input type="button" value="Search" onclick="Search();" />
</div>
<div>
<p>Approx. <span id="Count">0</span> results.</p>
<ul id="Results">
</ul>
</div>
Безусловно, страница должна также содержать элемент управления
ScriptManager. В его подэлементе <Services> следует указать ссылку на
вебслужбу – файл .asbx. Кроме того, нужно загрузить библиотеку сце
нариев PreviewScript.js (глава 15), поскольку она будет использоваться
программным кодом JavaScript.
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/Google.asbx" />
</Services>
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
Этот фрагмент загрузит реализацию моста и сделает доступным в Java
Script наше пространство имен OReilly.AspNetAJAX. После этого можно
вызвать метод обертки Search(), как если бы это была обычная локаль
ная вебслужба. Обратите внимание на то, как передаются параметры, –
в виде массива, в котором имена параметров служат индексами:
OReilly.AspNetAJAX.Google.Search(
{ "query": query },
callComplete, callError
);
Использование веб"службы Google 391
list.removeChild(list.firstChild);
}
}
function Search() {
var query = new Sys.Preview.UI.TextBox($get('Query'))
$get("Button").disabled = true;
clearList();
OReilly.AspNetAJAX.Google.Search(
{ "query": query.get_text() },
callComplete, callError
);
new Sys.Preview.UI.Label($get('Count')).set_text("...");
}
function callComplete(result) {
new
Sys.Preview.UI.Label($get('Count')).set_text(result.estimatedTotalResultsCount);
if (result.resultElements != null) {
for (var i = 0; i < result.resultElements.length; i++) {
var page = result.resultElements[i];
var li = document.createElement("li");
var a = document.createElement("a");
a.setAttribute("href", page.URL);
a.innerHTML = page.title;
li.appendChild(a);
$get("Results").appendChild(li);
}
}
$get("Button").disabled = false;
}
function callError(result) {
window.alert("Error! " + result.get_message());
new Sys.Preview.UI.Label($get('Count')).set_text("0");
$get("Button").disabled = false;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/Google.asbx" />
</Services>
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="Query" />
Использование веб"службы Amazon 393
При работе над этой книгой мне несколько раз пришлось столк
нуться с перебоями в работе сервера вебслужб Google, поэтому
не нужно сразу делать вывод об ошибках в программе, если вам
не удастся немедленно получить результаты. Это может быть
вызвано проблемами на удаленном сервере. В приложении A вы
найдете сведения об отладке Ajaxприложений и способы изуче
ния HTTPтрафика.
function join(a) {
var s = "";
for (var i=0; i < a.length 1; i++) {
s += a[i] + "/";
}
s += a[a.length 1];
return s;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/Amazon.asbx" />
</Services>
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="Query" />
<input type="button" id="Button" value="Search" onclick="Search();" />
</div>
<div>
<p>
<span id="Count">0</span> results.</p>
<ul id="Results">
398 Глава 18. Использование внешних веб"служб
</ul>
</div>
</form>
</body>
</html>
<method name="Search">
<input>
<parameter name="licenseKey"
value="% appsettings : GoogleLicenseKey %"
serverOnly="true" />
<parameter name="query" />
</input>
</method>
<method name="SearchXslt" serverName="Search">
<input>
<parameter name="licenseKey"
value="% appsettings : GoogleLicenseKey %"
serverOnly="true" />
<parameter name="query" />
</input>
<transforms>
<transform type="Microsoft.Web.Preview.Services.XmlBridgeTransformer" />
<transform type="Microsoft.Web.Preview.Services.XsltBridgeTransformer">
<data>
<attribute name="stylesheetFile" value="~/Google.xsl" />
</data>
</transform>
</transforms>
</method>
</bridge>
Теперь все, что осталось сделать, – это обратиться к мосту. Поскольку
мост возвращает фрагмент разметки HTML, то результаты, получен
ные от вебслужбы, можно просто записать в свойство innerHTML кон
тейнера <div>. Это существенно упрощает сценарий JavaScript.
В примере 18.10 приводится полная страница ASP.NET с разметкой
и программным кодом JavaScript. Результат работы этой страницы
идентичен результату работы примера 18.3 и показан на рис. 18.3.
Пример 18.10. Вызов вебслужбы Google с XSLпреобразованием результатов
GoogleXslt.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
<script language="JavaScript" type="text/javascript">
function clearList() {
$get("Results").innerHTML = "";
}
function Search() {
var query = new Sys.Preview.UI.TextBox($get('Query'))
Преобразование результатов веб"службы с помощью XSLT 403
$get("Button").disabled = true;
clearList();
OReilly.AspNetAJAX.Google.SearchXslt(
{ "query": query.get_text() },
callComplete, callError
);
}
function callComplete(result) {
$get("Results").innerHTML = result;
$get("Button").disabled = false;
}
function callError(result) {
window.alert("Error! " + result.get_message());
$get("Button").disabled = false;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/Google.asbx" />
</Services>
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="Query" />
<input type="button" id="Button" value="Search" onclick="Search();" />
</div>
<div id="Results">
</div>
</form>
</body>
</html>
Безусловно, такой подход пригоден и для работы с вебслужбой Ama
zon. Прежде всего, необходимо изменить файл моста. В примере 18.11
приводится новый код разметки.
Пример 18.11. Измененная версия моста для доступа к вебслужбе Amazon
Amazon.asbx
<?xml version="1.0" encoding="utf 8" ?>
<bridge namespace="OReilly.AspNetAJAX" className="Amazon" >
<proxy type="AWSECommerceServiceWrapper, App_Code" />
<method name="Search">
<input>
404 Глава 18. Использование внешних веб"служб
<parameter name="accessKey"
value="% appsettings : AmazonAccessKey %"
serverOnly="true" />
<parameter name="query" />
</input>
</method>
<method name="SearchXslt" serverName="Search">
<input>
<parameter name="accessKey"
value="% appsettings : AmazonAccessKey %"
serverOnly="true" />
<parameter name="query" />
</input>
<transforms>
<transform type="Microsoft.Web.Preview.Services.XmlBridgeTransformer" />
<transform type="Microsoft.Web.Preview.Services.XsltBridgeTransformer">
<data>
<attribute name="stylesheetFile" value="~/Amazon.xsl" />
</data>
</transform>
</transforms>
</method>
</bridge>
Кроме того, в классеобертке необходимо реализовать фиктивную функ
цию для перенаправления обращений SearchXslt() методу Search(), как
показано в примере 18.12.
Пример 18.12. Измененная версия классаобертки для доступа
к вебслужбе Amazon
AWSECommerceServiceWrapper.cs
using Amazon;
public class AWSECommerceServiceWrapper
{
public Amazon.Items Search(string accessKey, string query)
{
ItemSearchRequest searchRequest = new ItemSearchRequest();
searchRequest.Keywords = query;
searchRequest.ResponseGroup = new string[] { "Small" };
searchRequest.SearchIndex = "Books";
ItemSearch search = new ItemSearch();
search.AWSAccessKeyId = accessKey;
search.Request = new ItemSearchRequest[1] { searchRequest };
AWSECommerceService awse = new AWSECommerceService();
ItemSearchResponse searchResponse = awse.ItemSearch(search);
return searchResponse.Items[0];
}
public Amazon.Items SearchXslt(string accessKey, string query)
Преобразование результатов веб"службы с помощью XSLT 405
{
return Search(accessKey, query);
}
}
Затем необходимо описать XSLпреобразование, которое будет кон
вертировать XMLдокумент, полученный от SOAPслужбы Amazon,
в HTML. В примере 18.13 представлен один из возможных вариантов.
Пример 18.13. Таблица стилей для преобразования результатов вызова
вебслужбы Amazon в HTML
Amazon.xsl
<?xml version="1.0" encoding="utf 8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf 8" omit xml declaration="yes" />
<xsl:template match="/">
<p>
<xsl:value of select="//TotalResults" /> matches found!
<ul>
<xsl:for each select="//Items/Item/ItemAttributes">
<li>
<xsl:value of select="Author" />:
<xsl:value of select="Title" />
</li>
</xsl:for each>
</ul>
</p>
</xsl:template>
</xsl:stylesheet>
Наконец, для запуска трансформации используется программный код,
очень похожий на пример 18.10. В примере 18.14 содержится полный
листинг.
Пример 18.14. Вызов вебслужбы Amazon с XSLпреобразованием результатов
AmazonXslt.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC " //W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1 transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
<script language="JavaScript" type="text/javascript">
function clearList() {
$get("Results").innerHTML = "";
406 Глава 18. Использование внешних веб"служб
}
function Search() {
var query = new Sys.Preview.UI.TextBox($get('Query'))
$get("Button").disabled = true;
clearList();
OReilly.AspNetAJAX.Amazon.SearchXslt(
{ "query": query.get_text() },
callComplete, callError
);
}
function callComplete(result) {
$get("Results").innerHTML = result;
$get("Button").disabled = false;
}
function callError(result) {
window.alert("Error! " + result.get_message());
$get("Button").disabled = false;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/Amazon.asbx" />
</Services>
<Scripts>
<asp:ScriptReference Assembly="Microsoft.Web.Preview"
Name="PreviewScript.js" />
</Scripts>
</asp:ScriptManager>
<div>
<input type="text" id="Query" />
<input type="button" id="Button" value="Search" onclick="Search();" />
</div>
<div id="Results">
</div>
</form>
</body>
</html>
На рис. 18.5 показан результат работы этой страницы. Здесь можно за
метить некоторые недостатки отображения. Например, элементы спи
ска с названиями изданий, для которых авторы не указаны, такие как
энциклопедии и прочие справочники, начинаются с символа двоето
чия. Этот недостаток проще было бы устранить с помощью программ
ного кода, но то же самое можно сделать и с помощью XSL.
Использование веб"службы Yahoo! (а также REST и XPath) 407
Коротко о REST
Название REST происходит от английского «REpresential State
Transfer» (передача данных о состоянии). Концепция REST де
тально описана Роем Филдингом (Roy Fielding) в его докторской
диссертации (Университет штата Калифорния) «Architectural
Styles and the Design of Networkbased Software Architectures»
(«Архитектурные стили и проектирование архитектур сетевого
ПО»). (Филдинг является одним из авторов спецификаций
HTTP.) Теоретические основы REST не имеют отношения к на
шим примерам, поэтому мы не будем углубляться в детали. Нам
достаточно знать, что RESTинтерфейс вызова вебслужб рабо
тает примерно следующим образом: серверу передается запрос
GET (!), все данные запроса (какой метод вызывается, какие аргу
менты передаются) становятся частью строки URL. Возвращае
мые данные обычно имеют формат XML, но могут использовать
ся и другие форматы, например простой текст, CSV или JSON.
408 Глава 18. Использование внешних веб"служб
http://api.search.yahoo.com/WebSearchService/V1/
webSearch?appid=***&output=xml&query=***
Эта строка URL содержит базовую часть (http://api.search.yahoo.com/
WebSearchService/V1/webSearch) и ряд аргументов, входящих в стро
ку запроса. Мост для этого примера (в файле .asbx) настроен на отправ
ку запросов приложения по этому URL.
function Search() {
var query = new Sys.Preview.UI.TextBox($get('Query'))
$get("Button").disabled = true;
clearList();
OReilly.AspNetAJAX.Yahoo.Search(
{ "query": query.get_text() },
callComplete, callError
);
}
function callComplete(result) {
for (var i = 0; i < result.length; i++) {
var li = document.createElement("li");
var a = document.createElement("a");
a.setAttribute("href", result[i].resultUrl);
a.innerHTML = result[i].resultTitle;
li.appendChild(a);
$get("Results").appendChild(li);
}
$get("Button").disabled = false;
}
function callError(result) {
window.alert("Error! " + result.get_message());
$get("Button").disabled = false;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
Использование веб"службы Yahoo! (а также REST и XPath) 415
Подведение итогов
В этой главе были продемонстрированы интереснейшие возможности
пакета ASP.NET AJAX Futures: вызов внешних вебслужб, преодоле
ние ограничений системы безопасности, заложенных в объект XMLHttp
Request, с помощью моста на стороне сервера.
_target
Целевой элемент анимации
Всякий раз, когда выполняется очередной шаг анимации, вызывается
метод setValue(). Выполняемые этим методом действия зависят от его
реализации. Это может быть метод отдельного анимационного эффек
та или метод setValue() класса Sys.Preview.UI.Effects.Animation, базово
го для всех анимационных эффектов. В зависимости от вида анима
ции, реализация метода может производить весьма сложные вычисле
ния или просто переходить к следующему элементу массива.
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server" ID="ScriptManager1">
<Scripts>
<asp:ScriptReference name="PreviewScript.js"
assembly="Microsoft.Web.Preview" />
<asp:ScriptReference name="PreviewGlitz.js"
assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<div>
<label id="Label1" style="display: inline block; background color: Red;">
See me fading ...</label>
</div>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<label id="Label1" />
<fadeAnimation id="ani" target="Label1" effect="FadeOut" />
<application>
<load>
<invokeMethodAction target="ani" method="play" />
</load>
</application>
</components>
</page>
</script>
</body>
</html>
</Scripts>
</asp:ScriptManager>
<div>
<label id="Label1" style="background color: Red; position: relative;">
See me moving ...</label>
</div>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<label id="Label1" />
</components>
</page>
</script>
</body>
</html>
Как только страница будет полностью загружена, элемент label начи
нает перемещаться по странице под углом 45 градусов. Обратите вни
мание, как используется свойство CSS position: relative для обеспече
ния такой возможности – вам необходимо только задать позицию эле
мента. Результат работы страницы приводится на рис. 19.2.
Использование LengthAnimation
для перемещения элемента
Предыдущий пример также может быть реализован декларативно.
Как отмечалось ранее, чтобы гарантировать воспроизведение анима
ционного эффекта во всех броузерах, свойствам top и left должны при
сваиваться значения, содержащие единицы измерения. При использо
вании класса NumberAnimation это возможно только в случае создания
своего собственного метода setValue().
Однако платформа ASP.NET AJAX предоставляет еще один класс –
LengthAnimation, который способен решить эту задачу более непосредст
венным способом.
426 Глава 19. Использование анимационных эффектов
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>ASP.NET AJAX</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server" ID="ScriptManager1">
<Scripts>
<asp:ScriptReference name="PreviewScript.js"
assembly="Microsoft.Web.Preview" />
<asp:ScriptReference name="PreviewGlitz.js"
assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
<div>
<label id="Label1" style="background color: Red; position: relative;">
See me moving ...</label>
</div>
</form>
<script type="text/xml script">
<page xmlns:script="http://schemas.microsoft.com/xml script/2005">
<components>
<label id="Label1">
<behaviors>
<layoutBehavior id="Label1Style" />
</behaviors>
</label>
<lengthAnimation id="ani1" target="Label1Style" duration="3"
property="left" startValue="0" endValue="300" />
<lengthAnimation id="ani2" target="Label1Style" duration="3"
property="top" startValue="0" endValue="300" />
<application>
<load>
<invokeMethodAction target="ani1" method="play" />
<invokeMethodAction target="ani2" method="play" />
</load>
</application>
</components>
</page>
</script>
</body>
</html>
Подведение итогов
Пакет ASP.NET AJAX Futures предлагает несколько анимационных
эффектов, которые могут использоваться для оживления или измене
ния элементов. Все анимационные эффекты могут быть применены
как программно, так и декларативно, что обеспечивает максимальную
гибкость в процессе разработки.
Исправление недостатков
программным способом
Понимание причины – отсутствие изменений в строке URL – приводит
к простому решению проблемы установки закладок: всякий раз, когда
изменяется текущее состояние страницы, информация о состоянии
должна помещаться в хеш строки URL текущей страницы. Всякий
раз, когда страница загружается после использования закладки,
к странице должны применяться данные из хеша URL, чтобы привес
ти ее в состояние, соответствующее моменту установки закладки. Для
этого потребуются две части программного кода на JavaScript. Первая
часть, что приводится ниже, сохраняет информацию об изменениях
состояния странице в хеше:
function somethingChanged() {
location.hash = "#" + getCurrentPageState();
}
Вторая часть запускается при первоначальной загрузке страницы. Ес
ли в хеше строки URL присутствует какаялибо информация, она
должна быть применена к текущей странице:
function pageLoad() {
if (location.hash.length > 0) {
applyPageState(location.hash);
}
}
Исправление недостатков программным способом 433
Предупреждение об опасности:
ловушки с закладками
При проверке степени безопасности страниц, использующих ме
тодику сериализации состояния, я нередко обнаруживаю, что
для этих целей используется формат JSON. В некоторых веб
страницах, поддерживающих закладки, сериализация состоя
ния страницы выполнена посредством записи элементов страни
цы и их значений или содержимого в виде строки формата
JSON, примерно так, как показано ниже:
{"TextBox1":"My Data","Label1":"Some other data","DropDownList1":"2"}
Затем эти данные кодируются в формат URL (с помощью Java
Scriptфункции escape()) и добавляются в конец строки URL. До
этого места данный подход еще не вызывает никаких проблем.
Сложности начинаются, когда дело доходит до восстановления
состояния страницы в соответствии с данными, находящимися
в строке URL. Самый простой способ снова преобразовать строку
JSON в объект JavaScript – это воспользоваться функцией
eval(), как показано ниже:
var o = eval("(" + location.hash.substring(1) + ")");
Потратим минуту времени на изучение этого кода. Данные из
строки URL интерпретируются как программный код на Java
Script. Это классический пример атаки типа межсайтовый скрип
тинг (CrossSite Scripting – XSS), представляющей серьезную уг
розу. Атакующий может разработать вредоносный программ
ный код на JavaScript, добавить его в конец URL страницы и за
тем передать этот URL жертве. При обращении по такому URL
броузер жертвы выполнит вредоносный код JavaScript.
Вы всегда должны исходить из предположения, что информация
в строке URL может быть изменена злоумышленником. Поэтому
не используйте ее для помещения важной или секретной инфор
мации и будьте особенно осторожны при применении этой ин
формации к странице.
434 Глава 20. Кнопки Назад/Вперед и закладки
{
Wizard1.ActiveStepIndex = step;
}
UpdatePanel1.Update();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<nk:UpdateHistory ID="UpdateHistory1" runat="server"
OnNavigate="historyNavigate" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server"
UpdateMode="Conditional">
<ContentTemplate>
<asp:Wizard ID="Wizard1" runat="server"
OnActiveStepChanged="stepChanged">
<WizardSteps>
<asp:WizardStep runat="server" Title="Step 1">
<h1>Ready ...</h1>
</asp:WizardStep>
<asp:WizardStep runat="server" Title="Step 2">
<h1>Set ...</h1>
</asp:WizardStep>
<asp:WizardStep runat="server" Title="Step 3">
<h1>Go!</h1>
</asp:WizardStep>
</WizardSteps>
</asp:Wizard>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
На рис. 20.1 показано, как выглядит страница сразу после загрузки.
Обратите внимание, как изменилась строка URL после перехода ко
второму шагу мастера (рис. 20.2)1. Щелчок на кнопке броузера Назад
должен выполнить возврат к первому шагу мастера. Если скопировать
строку URL из рис. 20.2 в другой броузер, этот броузер тоже должен
отобразить страницу на втором шаге мастера (рис. 20.3), что доказыва
ет наличие поддержки механизма закладок.
1 Отметим также, что автор вновь использует порт 1234 отладочного серве
ра, как это было в первых главах. – Примеч. науч. ред.
Исправление недостатков с помощью элемента управления UpdateHistory 439
}
protected void historyNavigate(object sender, HistoryEventArgs e)
{
int step = 0;
if (e.State.ContainsKey("myHistory"))
{
int.TryParse(e.State["myHistory"].ToString(), out step);
}
if (step >= 0 && step < Wizard1.WizardSteps.Count)
{
Wizard1.ActiveStepIndex = step;
}
UpdatePanel1.Update();
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>ASP.NET AJAX</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:History ID="History1" runat="server" OnNavigate="historyNavigate" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server"
UpdateMode="Conditional">
<ContentTemplate>
<asp:Wizard ID="Wizard1" runat="server"
OnActiveStepChanged="stepChanged">
<WizardSteps>
<asp:WizardStep runat="server" Title="Step 1">
<h1>Ready ...</h1>
</asp:WizardStep>
href="javascript:gotoStepClick(2)">Step 2</a></td>
</tr><tr>
<td id="Wizard1_SideBar3"><a
id="Wizard1_SideBarContainer_SideBarList_ctl02_SideBarButton"
href="javascript:gotoStepClick(3)">Step 3</a></td>
</tr>
</table></td><td style="height:100%;"><table cellspacing="0"
cellpadding="0" border="0" style="height:100%;width:100%;border
collapse: collapse;">
<tr id="Wizard1_Step1" style="height:100%;display:none;">
<td>
<h1>Ready ...</h1>
</td>
</tr>
<tr id="Wizard1_Step2" style="height:100%;display:none;">
<td>
<h1>Set ...</h1>
</td>
</tr>
<tr id="Wizard1_Step3" style="height:100%;display:none;">
<td>
<h1>Go!</h1>
</td>
</tr>
</table></td>
</tr>
</table>
</form>
</body>
</html>
Подведение итогов
В этой главе вы познакомились с двумя известными проблемами, при
сущими многим Ajaxприложениям: недостатки в поддержке механиз
ма закладок и неработающие кнопки броузера Назад и Вперед. В этой
главе также были даны варианты решения этих проблем. Это может
потребовать дополнительных усилий, но удобство использования стра
ниц с поддержкой Ajax при этом существенно повысится.
Рис. 21.1. Элементы управления из пакета ASP.NET AJAX Futures CTP Web
Parts поддерживают возможность перемещения мышью в броузерах Mozilla
ASP.NET AJAX и ASP.NET Web Parts 453
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
<asp:WebPartManager ID="WebPartManager1" runat="server" />
<table>
<tr>
<td>
<asp:WebPartZone ID="WebPartZone1" HeaderText="Zone 1"
runat="server">
<ZoneTemplate>
<asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
</ZoneTemplate>
</asp:WebPartZone>
</td>
<td>
<asp:WebPartZone ID="WebPartZone2" HeaderText="Zone 2"
runat="server">
<ZoneTemplate>
<asp:Wizard ID="Wizard1" runat="server">
<WizardSteps>
<asp:WizardStep ID="Step1" runat="server"
Title="Step 1" />
<asp:WizardStep ID="Step2" runat="server"
Title="Step 2" />
</WizardSteps>
</asp:Wizard>
</ZoneTemplate>
</asp:WebPartZone>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
Подведение итогов
В этой главе был исследован один из уникальных подходов к использо
ванию (и многократному использованию) компонентов ASP.NET AJAX.
В настоящее время вебчасти используются довольно редко, но начало
уже положено. В отличие от своих аналогов в ASP.NET 2.0, вебчасти из
ASP.NET AJAX Futures CTP работают в броузерах любого типа.
function callComplete(result) {
window.alert(result);
}
function callError(result) {
window.alert("Error! " + result);
}
</script>
</head>
<body>
<form id="form1">
<div>
<input type="text" id="name" name="name" />
<input type="button" value="Call Service"
onclick="callService(this.form);" />
</div>
</form>
</body>
</html>
Подведение итогов
В этой главе было показано, как работать с ASP.NET AJAX из PHP, ис
пользуя библиотеку Microsoft AJAX Library из другой серверной тех
нологии (и при желании – из другой операционной системы). Клиент
ские компоненты ASP.NET AJAX легко могут использоваться с други
ми языками программирования, так как сам JavaScript является плат
формонезависимым; работу серверных компонентов, с другой стороны,
необходимо имитировать. Эта имитация, разумеется, не связана с оп
ределенным языком, так, скажем, пример в этой главе можно было бы
написать на JSP, Perl, ColdFusion или даже на классическом ASP.
Проект PHP for Microsoft AJAX облегчает использование ASP.NET
AJAX для PHP, поскольку большая часть хитроумного программного
кода (такого как создание объектапосредника на JavaScript) уже реа
лизована.
Инструменты отладки
На вопрос: «Какой способ отладки JavaScript в процессе разработки
самый лучший?», многие разработчики отвечают: «Отказаться от
Internet Explorer». Несмотря на то, что самые последние версии всех
основных броузеров действительно отличаются высоким качеством,
степень подробности сообщений об ошибках у них разная. Internet Ex
plorer дает самые неинформативные сообщения. Взгляните, какие со
общения об одной и той же ошибке генерируют различные броузеры.
На рис. A.1 показано сообщение в Firefox, которое включает в себя но
мер строки, имя файла, а также (после щелчка на имени файла) сам
программный код, вызвавший ошибку. Не так много, но с этим, по
466 Приложение A
ment Helper. После этого Internet Explorer отобразит окно этой над
стройки в верхней части страницы. Расширение Web Development
Helper не только обеспечивает доступ к информации в странице, но
и обладает некоторыми функциональными возможностями платфор
мы ASP.NET, такими как ViewState и вывод трассировочной информа
ции (особенности, которые в настоящее время отсутствуют в Firebug).
С его помощью можно также активизировать возможность журнали
рования трафика HTTP и даже создавать снимки экрана. Интерфейс
расширения Web Development Helper показан на рис. A.4.
Отладка приложений ASP.NET AJAX 469
в режиме отладки (это объясняет, почему так мало людей знают о его
существовании) через пункт меню Debug→Windows→Script Explorer.
Также поддерживается возможность настроить Visual Studio так, что
бы окно Script Explorer отображалось по умолчанию.
Откройте Script Explorer. После этого вы сможете открыть любой
файл JavaScript, загруженный текущей страницей, и выполнять сле
дующие действия:
• Произвести пошаговое выполнение кода
• Просмотреть содержимое текущих переменных
• Выполнять команды JavaScript и многое другое
На рис. A.8 показан сеанс отладки с использованием Script Explorer.
472 Приложение A
Отладка в Firefox
После установки расширения Firebug вы получаете все, что не
обходимо для отладки, поскольку Firebug включает в себя эти
инструменты. Когда сценарий запускает отладчик – например,
выполняет инструкцию отладчика – в действие вступает Firebug
и отображает текущую исполняемую строку сценария, как пока
зано на рис. A.9.
Для Firefox существует еще один очень интересный отладчик
JavaScript, который называется Venkman (его можно загрузить
со страницы https://addons.mozilla.org/firefox/addon/216). Он
предоставляет все, что требуется от отладчика, за исключением
возможностей интегрированной среды разработки, которые мо
жет предложить Visual Studio. С другой стороны, отладчик Venk
man очень удобно интегрируется в броузер. Для запуска отлад
чика нужно выбрать пункт меню Инструменты→JavaScript De
bugger (Tools→JavaScript Debugger).
Обратите внимание: в некоторых версиях Firefox проявляется
досадная ошибка при использовании отладчика Venkman – вы
можете открыть окно отладчика только один раз в течение сеан
са работы с броузером. В этом случае, чтобы повторно запустить
отладчик, вам потребуется перезапустить броузер. Поэтому
в процессе отладки приложения лучше держать окно отладчика
открытым постоянно. На рис. A.10 показано, как выглядит от
ладчик Venkman.
474 Приложение A
Sys.Debug.clearTrace()
Выполняется очистка консоли.
Sys.Debug.fail(message)
В консоль выводится сообщение message и запускается отладчик.
Sys.Debug.trace(text)
В консоль выводится содержимое аргумента text.
Sys.Debug.traceDump(object, name)
В консоль выводится содержимое объекта object (включая содер
жимое всех его членов и необязательного аргумента name!).
В примере A.1 демонстрируется использование некоторых из этих ме
тодов на базе последнего примера из главы 5, в котором производится
вызов вебслужбы. Для работы этого примера необходимо присутствие
на сервере файла MathService.asmx из главы 5 (версия, которая под
держивает метод ExtendedDivideNumbers()).
Прежде чем будет вызвана вебслужба, в консоль JavaScript выводит
ся информация, включающая сведения об объектепосреднике Java
Script MathService:
Sys.Debug.trace("Calling MathService");
Sys.Debug.traceDump(MathService, "MathService: ");
Данные, полученные от службы, также выводятся в консоль:
Sys.Debug.trace("Received result!");
Sys.Debug.traceDump(result, "result: ");
В случае появления ошибки текст сообщения отображается в консоли
JavaScript (в зависимости от типа броузера и его настроек). Затем сце
нарий выходит в отладчик JavaScript (если таковой имеется):
function callError(result) {
Sys.Debug.fail(
result.get_exceptionType() +
": " +
result.get_message() +
"\n" +
result.get_stackTrace());
}
Полный программный код приводится в примере A.1, а на рис. A.11
показано, как могут выглядеть полученные результаты в броузере. Вся
прелесть поддержки отладки в ASP.NET AJAX заключается в том, что
этот программный код оказывает влияние на страницу только в режи
ме отладки. Если приложение настроено или страница запускается
в рабочем режиме, в консоль JavaScript не передается никаких данных.
Благодаря этому отпадает необходимость удалять из приложения отла
дочный код, исключение составляет элемент <textarea>, используемый
в качестве консоли (если таковой присутствует). С другой стороны, если
476 Приложение A
function callComplete(result) {
Sys.Debug.trace("Received result!");
Sys.Debug.traceDump(result, "result: ");
document.getElementById("c").innerHTML =
result.result +
" (calculated at " +
result.calculationTime +
")";
}
function callError(result) {
Sys.Debug.fail(
result.get_exceptionType() +
": " +
result.get_message() +
"\n" +
result.get_stackTrace());
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"
ScriptMode="Debug">
<Services>
<asp:ServiceReference Path="MathService.asmx" />
</Services>
</asp:ScriptManager>
<div>
<nobr>
<input type="text" id="a" name="a" size="2" />
:
<input type="text" id="b" name="b" size="2" />
=
<span id="c" style="width: 50px;"></span>
</nobr>
<br />
<input type="button" value="Divide Numbers"
onclick="callService(this.form);" />
<br />
<textarea id="TraceConsole" rows="10" cols="50">Debug information:
</textarea>
</div>
</form>
</body>
</html>
478 Приложение A
Подведение итогов
Это приложение должно было развеять ложное мнение о том, что Ajax
приложения невозможно отлаживать. В действительности существует
несколько возможностей и инструментальных средств. Хотя отладка
Windowsприложений остается значительно более удобно организо
ванной, однако JavaScript постепенно приближается к этому уровню.
Методы
Метод Описание
abort() Завершает запрос и отбрасывает любой ответ
getAllResponseHeaders() Возвращает все заголовки из HTTPответа
getResponseHeader(header) Возвращает значение заданного заголовка
из HTTPответа
open(method, url, async, Создает HTTPзапрос и подготавливает его к от
username,password) правке заданным методом (GET или POST) по за
данному URL. Остальные параметры являются
необязательными: использовать или не использо
вать асинхронный (по умолчанию) режим отправ
ки запроса и данные для HTTPаутентификации.
(Обратите внимание: данные для аутентификации
480 Приложение B
Метод Описание
отправляются в простом текстовом виде – если вас
беспокоит вопрос безопасности, используйте для
работы со страницей протокол HTTPS.)
send(content) Отправляет HTTPзапрос – в необязательном ар
гументе можно указать дополнительные данные,
которые будут отправлены вместе с запросом
(POSTинформация)
setRequestHeader(name, Добавляет к HTTPзапросу заголовок с заданным
value) именем и значением
Свойства
Свойство Описание
readyState Состояние HTTPзапроса (0=uninitialized, 1=loading,
2=loaded, 3=waiting, 4=complete)
responseText Данные, полученные в ответ на запрос, в виде текста
responseXML Данные, полученные в ответ на запрос, в виде объекта
XML DOM
status Код HTTPстатуса HTTPответа
statusText Сообщение HTTPстатуса HTTPответа
Справочник DOM
Методы
Метод Описание
appendChild(node) Добавляет дочерний узел в элемент
appendData(data) Добавляет в узел данные (код разметки HTML
или текст) – существующие данные при этом не
затираются
blur() Выносит фокус ввода из элемента
click() Имитирует щелчок мышью на элементе
cloneNode(deep) Создает копию узла (если аргумент deep имеет
значение true, выполняется копирование всех
вложенных узлов)
deleteData(start, length) Удаляет заданное число символов из данных узла
focus() Переносит фокус ввода в элемент
482 Приложение C
Метод Описание
getAttribute(attribute) Возвращает значение заданного атрибута
getAttributeNode(attribute) Возвращает узел, содержащий заданный атрибут
getElementsByTagName(name) Возвращает массив из всех элементов с заданным
именем тега
hasChildNodes() Возвращает значение, которое указывает, имеет
ли данный элемент вложенные узлы
insertBefore(node) Вставляет узел перед элементом
insertData(position, data) Вставляет данные (код разметки HTML или
текст) в указанную позицию
removeAttribute(attribute) Удаляет из элемента указанный атрибут и его
значение
removeChild(node) Удаляет из элемента указанный вложенный узел
replaceChild(newnode, Замещает указанный старый вложенный узел
oldnode) (oldnode) новым (newnode)
replaceData(start, length, Замещает данные (начиная с указанной позиции,
newdata) заданной длины) на новые
setAttribute(name, value) Присваивает заданное значение указанному атри
буту
setAttributeNode(node) Добавляет новый атрибут в виде узла, замещая
существующий
Свойства
Свойство Описание
attributes[] Массив атрибутов элемента и их значений (для чтения/записи)
childNodes[] Список вложенных узлов элемента (для чтения/записи)
className Имя CSSкласса элемента (для чтения/записи)
data Символьные данные в текстовом узле (для чтения/записи)
dir Направление чтения для элемента (для чтения/записи)
firstChild Первый вложенный узел элемента (для чтения)
id Идентификатор элемента (для чтения/записи)
innerHTML Разметка HTML, содержащаяся в элементе (не соответствует
стандартам W3C, но реализовано в большинстве броузеров)
(для чтения/записи)
lang Язык элемента (атрибут lang) (для чтения/записи)
lastChild Последний вложенный узел элемента (для чтения)
length Длина элемента (для чтения/записи)
localeName Код региональных настроек элемента (без пространства имен,
если таковое указано) (для чтения/записи)
Справочник DOM 483
Свойство Описание
namespaceURI Идентификатор URI пространства имен элемента (для чтения/
записи)
nextSibling Элемент, расположенный следующим после текущего в дереве
DOM (для чтения/записи)
nodeName Имя тега элемента узла (для чтения/записи)
nodeType Тип узла или элемента узла (для чтения/записи)
nodeValue Значение в узле элемента (для чтения/записи)
ownerDocument Документ, которому принадлежит данный элемент (для чтения)
parentNode Родительский узел элемента (для чтения)
prefix Префикс пространства имен, используемого узлом (для чте
ния/записи)
previousSib Элемент, расположенный перед текущим в дереве DOM (для
ling чтения/записи)
style Информация о стилях элемента (для чтения/записи)
tabIndex Порядковый номер элемента для передачи фокуса ввода клави
шей табуляции (для чтения/записи)
tagName Имя тега элемента (для чтения/записи)
title Заголовок элемента (для чтения/записи)
Методы
Метод Описание
clear() Очищает содержимое документа
close() Закрывает доступ на запись (открытый методом
open()) в документ
createAttribute(attribute) Создает атрибут с указанным именем
createDocumentFragment() Создает фрагмент документа
createElement(name) Создает элемент с заданным именем тега
createTextNode(text) Создает текстовый узел с заданным текстом
getElementById(id) Возвращает элемент с указанным идентификатором
getElementsByTagName(name) Возвращает массив всех элементов с указанным
именем тега
open(mime, replace) Открывает документ для записи, устанавливает
MIMEтип и, если необязательный параметр replace
484 Приложение C
Метод Описание
имеет значение true, замещает прежнее содержи
мое документа (в противном случае новое содержи
мое добавляется в конец документа)
write(text) Записывает данные в документ
writeln(text) Записывает данные и комбинацию символов пере
вода строки (\r\n) в документ
Свойства
Свойство Описание
alinkColor Цвет активной ссылки (для чтения/записи)
anchors[] Массив всех якорных элементов в документе (для чтения)
applets[] Массив всех Javaапплетов в документе (для чтения)
bgColor Цвет фона документа (для чтения/записи)
body Тело документа (для чтения/записи)
compatMode Значение, которое указывает, должен ли механизм отобра
жения использовать режим совместимости с прежними вер
сиями Internet Explorer (для чтения/записи)
cookie Cookies, которые доступны из документа (для чтения/записи)
documentElement DOMузел документа (для чтения/записи)
domain Домен документа (для чтения)
embeds[] Массив всех внедренных объектов (для чтения/записи)
fgColor Цвет переднего плана (текста) документа (для чтения/записи)
forms[] Массив всех форм в документе. В страницах ASP.NET может
присутствовать только одна форма, которая всегда соответст
вует элементу массива forms[0] (для чтения/записи)
images[] Массив всех изображений в документе (для чтения)
lastModified Дата и время последнего изменения документа на сервере
(для чтения)
linkColor Цвет ссылок (для чтения/записи)
links[] Массив всех ссылок в документе (для чтения)
location Информация о строке URL документа (для чтения)
referrer URL документа, из которого пользователь перешел к текуще
му документу (для чтения)
styleSheets[] Массив всех каскадных таблиц стилей, ссылки на которые
имеются в документе (для чтения)
URL URL документа (для чтения)
vlinkColor Цвет для посещавшихся ссылок (для чтения/записи)
Справочник по ASP.NET AJAX
Вспомогательные функции
Платформа ASP.NET AJAX имеет несколько удобных вспомогатель
ных функций. Наиболее важные из них имеют сокращенные имена,
начинающиеся с символа доллара ($).
Свойство Описание
$addHandler(element, event Добавляет в элемент DOM обработчик указанно
Name, handler); го события
$addHandlers(element, Добавляет в элемент DOM несколько обработчи
events, handlerOwner) ков событий
$clearHandlers(element) Удаляет все обработчики событий, присоеди
ненные к элементу DOM
$create(type, properties, Создает компонент и инициализирует его
events, references, element)
$find(id, parent) Отыскивает компонент с указанным идентифи
катором
$get(id, element) Отыскивает элемент DOM с указанным иденти
фикатором
$removeHandler(element, Удаляет указанный обработчик события из эле
eventName, handler) мента DOM
486 Приложение D
Расширения объектов
Платформа ASP.NET AJAX расширяет некоторые стандартные объек
ты JavaScript, такие как строки или логические значения, дополни
тельными методами. Расширения JavaScriptобъекта Error использу
ются преимущественно внутренней реализацией платформы, однако
расширения других объектов также могут использоваться программи
стами при разработке своего кода.
ScriptManager
Элемент управления ScriptManager является самым важным для сай
тов, построенных на базе платформы ASP.NET AJAX, поскольку он
отвечает за загрузку клиентских библиотек, а также занимается соз
данием объектовпосредников.
Свойства
Свойство Описание
AllowCustomErrorsRedirect Разрешает (true, по умолчанию) или запрещает
(false) перенаправление ошибок (определяемое
в файле Web.config), возникающих на сервере
в процессе обработки асинхронных запросов
AsyncPostBackErrorMessage Текст сообщения об ошибке, возникшей в про
цессе выполнения асинхронного запроса
AsyncPostBackSourceElementID Идентификатор элемента, инициировавшего
асинхронный запрос
AuthenticationService Path Путь к службе аутентификации
490 Приложение E
Свойство Описание
EnablePageMethods Разрешает (true) или запрещает (false, по
умолчанию) использование статических встро
енных методов (методов страницы)
EnablePartialRendering Разрешает (true, по умолчанию) или запреща
ет (false) возможность частичного отображе
ния, реализованную в UpdatePanel
EnableScriptGlobalization Разрешает (true) или запрещает (false, по
умолчанию) использование региональных на
строек из ASP.NET AJAX
EnableScriptLocalization Разрешает (true) или запрещает (false, по
умолчанию) использование локализованного
содержимого из ASP.NET AJAX
LoadScriptsBeforeUI Определяет, когда следует загружать библио
теки JavaScript – до (true, по умолчанию) или
после (false) разметки страницы
ProfileService LoadProperties Свойства профиля, доступные клиентскому
сценарию
ProfileService Path Путь к вебслужбе управления профилями
ScriptMode Определяет, какую версию библиотек следует
использовать – отладочную или рабочую
ScriptPath Корневой каталог для пользовательских биб
лиотек JavaScript и библиотек ASP.NET AJAX
AuthenticationService
Элемент <Authentication>, дочерний по отношению к элементу управле
ния ScriptManager используется для организации поддержки службы
аутентификации. Обладает следующим свойством:
Свойство Описание
Path Путь и имя файла вебслужбы аутентификации
ProfileService
Элемент <ProfileService>, дочерний по отношению к элементу управле
ния ScriptManager используется для организации поддержки службы
управления профилями. Обладает следующим свойством:
Свойство Описание
LoadProperties Содержит список свойств профиля, которые должны
быть доступны клиентскому сценарию
Справочник по ScriptManager, UpdatePanel, UpdateProgress и Timer 491
Scripts
Элемент <Scripts>, дочерний по отношению к элементу управления
ScriptManager содержит все клиентские сценарии, которые будут загру
жены с помощью элемента управления <asp:ScriptReference>. Обладает
следующими свойствами.:
Свойство Описание
Assembly Сборка, в которой содержится сценарий
IgnoreScriptPath Определяет, следует игнорировать (true) свойство
ScriptPath элемента управления ScriptManager или нет
(false, по умолчанию)
Name Имя используемого встроенного ресурса сценария
NotifyScriptLoaded Определяет, следует (true, по умолчанию) или нет (false)
автоматически добавлять в конец сценария программ
ный код, который будет извещать элемент управления
ScriptManager о том, что сценарий был загружен
Path Путь и имя файла загружаемого сценария
ResourceUICultures Список используемых культур пользовательского ин
терфейса
ScriptMode Определяет, какую версию сценария следует использо
вать – отладочную (Debug) или рабочую (Release)
Path Путь и имя файла вебслужбыуправления профилями
UpdatePanel
Благодаря элементу управления UpdatePanel можно выполнять обнов
ление отдельного раздела страницы с поддержкой ASP.NET AJAX не
зависимо от остальной части страницы; содержимое должно разме
щаться в элементе <ContentTemplate>, вложенном в <asp:UpdatePanel>.
Свойства
Свойство Описание
ChildrenAsTriggers Определяет, должно ли (true, по умолчанию) обновлять
ся содержимое элемента UpdatePanel при получении дан
ных дочерними элементами или нет (false)
RenderMode Определяет, как должно отображаться содержимое эле
мента управления UpdatePanel – в виде элемента <div>
(Block, по умолчанию) или <span> (Inline)
UpdateMode Определяет, когда выполнять обновление, всегда (Al
ways, то есть при любом получении данных) или по усло
вию (Conditional, то есть только принудительно)
492 Приложение E
Triggers
Элемент <Triggers>, дочерний по отношению к элементу управления
UpdatePanel, содержит объектытриггеры, которые могут вызвать об
новление содержимого элемента управления UpdatePanel. Имеются два
триггера – <asp:AsyncPostBackTrigger> и <asp:PostBackTrigger>, со сле
дующими свойствами:
Свойство Описание
ControlID Идентификатор элемента управления, который может
вызвать обработчик
EventName Событие, которое возникает при срабатывании тригге
ра (только для <asp:AsyncPostBackTrigger>)
UpdateProgress
Элемент управления UpdateProgress отображает экранную заставку
(waiting screen), пока идет обновление элемента UpdatePanel. Фактиче
ское содержимое заставки размещается в элементе <ProgressTemplate>,
вложенном в элемент <asp:UpdateProgress>.
Свойства
Свойство Описание
AssociatedUpdatePanelID Идентификатор элемента управления UpdatePanel,
ассоциированного с данным элементом
DisplayAfter Длительность интервала времени в миллисекундах,
через которое будет показана экранная заставка (по
умолчанию 500)
DynamicLayout Определяет, следует ли резервировать пространство
на странице под заставку (false) или место должно
выделяться динамически, только после того, как
в этом появится необходимость (true, по умолчанию)
Timer
Элемент управления Timer запускает события и вызывает передачу
данных через заданные интервалы времени.
Свойства
Свойство Описание
Enabled Разрешает (true, по умолчанию) или запрещает
(false) срабатывания таймера
Interval Интервал времени в миллисекундах между срабаты
ваниями таймера (по умолчанию 60000)
Алфавитный указатель
A ASP.NET AJAX
ASP.NET Web Parts, 448
Accordion, элемент управления, 234 Control Toolkit
addCssClass(), метод, 298 Accordion, элемент управления,
$addHandler(), функция, 94, 263 234
$addHandlers(), функция, 94 использование, 216
AddHistoryPoint(), метод, 440 пакет элементов управления, 211
AdventureWorks, база данных, 148 содействие проекту, 268
установка, 32 создание собственных
Ajax компонентов, 258
JSON, 86 установка, 212
архитектура, 23 get_text(), метод, 287
и ASP.NET AJAX, 23 ScriptManager, элемент управления,
объект XMLDocument, 81 39
объект XMLHttpRequest, 69 set_text(), метод, 287
AjaxControlExtender, папка, 212 анимация
Always, режим, 155 группировка, 427
AlwaysVisibleControlExtender, элемент перемещение элемента, 422, 425
управления, 236 архитектура, 34
Amazon, вебслужба, 393 аспекты поведения
AnimationChildren, свойство, 227 Sys.Preview.UI.ClickBehavior, 342
AnimationExtender, элемент Sys.Preview.UI.FloatingBehav
управления, 221, 226 ior, 346
<anonymousIdentification>, элемент, использование, 341
165 аутентификация
API (Application Programming Inter подготовка приложения, 177
face), служба аутентификации, 180 базовые методы, 297
applyPageState(), функция, 433 гиперссылки, 290
Array, класс данные на стороне сервера, элемент
расширения, 486 управления ListView, 359
.asmx файл, 121 доступ к сгруппированным данным
ASP.NET, 25 в профиле, 171
Configuration, команда, 177 загрузка библиотек, 41
Web Application Administration использование с PHP, 458
Tool, 177 клиентские элементы управления,
вебчасти, 448 281
и ASP.NET AJAX, 25 использование, 282
обработка событий, 300
клиенты, 111
494 Алфавитный указатель
свойства службы
ASP.NET AJAX, 485 ASP.NET, 26
AsyncPostBackTrigger, 153 основные, 25
BackgroundCssClass, 250 служба аутентификации, 490
CollapseControlID, 247 служба управления профилями, 490
ControlID, 153 собственные валидаторы, 330
dataPath, 370 собственные преобразователи, 311
DOM, 482 собственные функции, создание, 54
DragHandleID, 229 события
_duration, 418 Tick, 153
Enabled, 349 для запуска анимации, 222
EventName, 153 для кнопок, 300
ExpandControlID, 247 для списков, 302
_fps, свойство, 418 добавление обработчиков, 95
HeaderText, 254 нажатия клавиш, 263
HorizontalSide, 236 обработка, 316
OKControlID, 250 в клиентских элементах управле
onreadystatechange, 74 ния, 300
PopupControlID, 250 с помощью сценариев, 46
PostBackTrigger, 153 совместимость, 25
property, 370 создание
responseText, 75 интерфейса с вкладками, 254
responseXML, 75 маркированного списка, 56
ScriptManager, элемент управления, постоянных ссылок, 446
489 собственных функций, 54
_target, 419 сообщения об ошибках, 119
TargetControlID, 221, 229, 247, 250, сопутствующие ресурсы, локализация,
349 192
Timer, элемент управления, 492 состояние сеанса, управление, 125
Triggers, 492 спам, блоги, 252
UpdatePanel, элемент управления, списки
491 HTML
UpdateProgress, элемент выбора, 373
управления, 492 привязка данных, 371
UserData, 165 выбора, 293
userName, 165 маркированные, 56
VerticalSide, 236 события, 302
visibilityMode, 330 сравнения операторы, 51
изменение значений через xmlscript, ссылки
317 WSDL (Web Services Description Lan
объекта XMLHttpRequest, 480 guage), 135
полей формы, 63 элементы управления, гиперссылки,
профиля, объявление, 165 290
элемента <binding>, 315 стандарты, объект XMLHttpRequest, 70
серверы, 25, 34 страницы методы, 121
ListView, элемент управления, 359 сценарии
программирование анимационных компоненты и элементы управления,
эффектов, 226 25
элементы управления, 26 локализация, 188
служба аутентификации поддержка, 491
вход и выход, 180 события, обработка, 46
Алфавитный указатель 507
Т AWSECommerceServiceWrapper.cs,
394
таблицы, HTML, 373 GoogleSearch.wsdl, 387
таймеры, 355 .htc, HTML control (элемент
теги управления HTML), 136
HTML, 314 MathService.asmx, 131
<invokeMethodAction>, 316 PHPHelloWorldService.php, 459
<script>, 46 PreviewDragDrop.js, 346
<setPropertyAction>, 316 PreviewGlitz.js, 417
текстовые PreviewScript.js, 346
гиперссылки, 290 TextBoxMaskBehavior.js, 260, 262
поля, 296 TextBoxMaskDesigner.cs, 260
типы TextBoxMaskExtender.cs, 260
анимационных эффектов, 223 Web.config, 165
базовые, 96, 99 моста к вебслужбе, 389, 395
типы данных вызов, 402
проверка, 327 ресурсов, добавление, 194
точки останова, 469 флажки, 292
формы
У ввода, 252
удаление обработчиков событий, 94 доступ к элементам, 61
удаленные вебслужбы предотвращение отправки, 338
доступ, 134 свойства полей, 63
управление спам, 252
асинхронными запросами, 159 функции
состоянием сеанса, 125 $addHandler(), 94, 263
управляющие конструкции JavaScript, $addHandlers(), 94
49 applyPageState(), 433
установка callComplete(), 413
ASP.NET AJAX, 28 $clearHandlers(), 94
Control Toolkit, пакет элементов doClick(), 181
управления, 212 eval(), 88
Firebug, 467 getCurrentPageState(), 433
Futures CTP, 33 getXMLHTTP(), 72
SQL Server Express, 32 gotoStepClick(), 443
интегрированной среды разработки, JavaScript, анонимные, 76
28 loginComplete(), 182
испытательной базы данных, 32 loginError(), 182
культуры, 195 pageLoad(), 95, 181
утилита для работы с исправлениями, pageNavigate(), 442
268 profileError(), 168, 174
profileLoaded(), 168
Ф $removeHandler(), 94, 263
saveProfile(), 169
файл моста к вебслужбе stateChanged(), 75
измененная версия, 403 вспомогательные, 93
кэширование запросов, 415 ASP.NET AJAX, 485
файлы собственные, создание, 54
.asmx, 121
AssemblyInfo.cs, 197
Authentication.aspx, 181
508 Алфавитный указатель
Ц <template>, 370
анимационный эффект перемеще
циклы ния, 422, 425
for, 52 произвольный доступ, 64
for...in, 53 страницы, доступ, 61
while, 53 элементы упарвления
Accordion, 234
Ч AlwaysVisibleControlExtender, 236
части страницы, 147 AnimationExtender, 221, 226
черный список, методика, 241 ASP.NET AJAX, 26
чтение AutoCompleteExtender, 238
данных профиля, 166 CalendarExtender, 246
сгруппированных данных в профиле, CollapsiblePanelExtender, 247
171 ConfirmButton, 216, 217
Control Toolkit, 216
Ш DragPanelExtender, 229
GridView, 147
шаблоны Image, 288
Control Toolkit, 212 Label, 148, 287
ListView, элемент управления, 360 ListView, 359
<ProgressTemplate>, 157 ModalPopupExtender, 250
собственных элементов управления, NoBot, 252
259 Repeater, 361
содержимого, 147 ScriptManager, 39, 489
Select, 294
Э TabContainer, 254
TabPanel, 254
экземпляры
Timer, свойства, 492
объектов от одного и того же базового
UpdateHistory, 435
класса, 105
UpdatePanel, 146, 436
элементы
область страницы, 146
<anonymousIdentification>, 165
UpdateProgress, 492
<authenticationService>, 179
WebPartManager, 450
<binding>, 315
WebPartZone, 450
<ContentTemplate>, 254
базовые методы, 297
<div>, 119
гиперссылки, 290
DOM, 96
клиентские, 281
<FadeOut>, 221
использование, 282
<floatingBehavior>, 346
обработка событий, 300
HTML, 314
проверка данных, 323
доступ, 286
кнопки, 292
позиционирование, 236
создание собственных элементов
<iframe>, 434
управления, 258
<itemTemplate>, 360
списки выбора, 293
<layoutTemplate>, 360
текстовые поля, 296
<Panes>, 234
флажки, 292
<proxy>, 389
эффект плавного исчезновения, 419
<span>, 119
<system.web>, 165
<system.web.extensions>, 166
<tagMapping>, 449
Алфавитный указатель 509
Я
языки
локализация сценариев, 188
языки программирования
JavaScript
встроенные объекты, 54
доступ к элементам страницы, 61
доступ к элементам форм, 61
массивы, 49
методы, 47
обзор, 46
ООП, 57
переменные, 48
управляющие конструкции, 49
По договору между издательством «СимволПлюс» и Интернетмага
зином «Books.Ru – Книги России» единственный легальный способ
получения данного файла с книгой ISBN 5932861223, название
«Программирование в ASP.NET AJAX» – покупка в Интернетмагази
не «Books.Ru – Книги России». Если Вы получили данный файл ка
кимлибо другим образом, Вы нарушили международное законода
тельство и законодательство Российской Федерации об охране автор
ского права. Вам необходимо удалить данный файл, а также сообщить
издательству «СимволПлюс» ([email protected]), где именно Вы по
лучили данный файл.