В состав проекта MVC Framework по умолчанию входят два JavaScript-файла: MicrosoftAjax.js и MicrosoftMvcAjax.js, в которых для разработчиков предложены вспомогательные функции при работе с Ajax. Рассмотрим их по порядку:
□ MicrosoftAjax.js — основной файл, который содержит всю инфраструктуру ASP.NET для работы с Ajax. Эта библиотека может быть знакома тем, кто использовал Ajax.NET или AjaxControlToolkit в проектах на базе классического ASP.NET;
□ MicrosoftMvcAjax.js — файл, осуществляющий поддержку Ajax в MVC-проектах, код которых написан с помощью специальных вспомогательных методов. Эта библиотека использует MicrosoftAjax.js для своей работы.
Для упрощения работы с Ajax MVC Framework содержит кроме JavaScript-файлов еще и расширения в виде классов и методов .NET. Так, класс viewPage, по умолчанию базовый для всех страниц MVC-проектов, содержит свойство Ajax, которое является экземпляром класса AjaxHelper.AjaxHelper содержит перечисленные в табл. 7.1 вспомогательные методы для работы с Ajax в представлениях.

Чтобы использовать данные расширения в своих проектах, необходимо подключить оба JavaScript-файла, MicrosoftAjax.js и MicrosoftMvcAjax.js, на необходимую страницу либо для всех страниц сразу через файл master-страницы. Код для добавления ссылок на эти файлы в master-странице может быть следующим:
<head runat="server">
<script src="<%= Url.Content("~/Scripts/MicrosoftAjax.debug.js") %>"
type="text/javascript">
</script>
<script src="<%=Url.Content("~/Scripts/MicrosoftMvcAj ax.debug.js") %>"
type="text/javascript"></script>
</head>
Далее мы рассмотрим более подробно эти вспомогательные методы и еще один вспомогательный класс AjaxOptions и свойство IsAjaxRequest, также имеющие отношение к Ajax.
Класс AjaxOptions представляет собой набор свойств, которые описывают разнообразные опции Ajax-запросов для вспомогательных методов MVC Framework. AjaxOptions содержит следующие свойства:
□ Confirm — задает текст, который будет выведен в запросе пользователю перед осуществлением запроса. Установка этого параметра приведет к тому, что перед запросом на сервер у пользователя будет возможность подтвердить отправку запроса или отменить ее (рис. 7.4);
Рис. 7.4. Запрос подтверждения при использовании параметра Confirm
□ HttpMethod — устанавливает тип HTTP-запроса (GET или POST), который будет использоваться при формировании асинхронного запроса. Может содержать одно из двух значений Get или Post, по умолчанию установлено в Post;
□ InsertionMode — свойство задает одно из значений одноименного перечисления InsertionMode: Replace, InsertBefore, InsertAfter. Значение по умолчанию Replace. Данное свойство устанавливает метод включения данных из ответа от сервера в элемент разметки: перезапись значения элемента, добавление до содержимого или после него. Данное свойство используется совместно со свойством UpdateTargetId, указывающим идентификатор элемента разметки, в которое будет записано значение результата ответа от сервера;
□ LoadingElementId — задает идентификатор элемента разметки, который должен быть отображен во время Ajax-запроса. Использование данного свойства приведет к тому, что указанный элемент будет показан во время запроса, а затем скрыт. Использование этого свойства имеет смысл для демонстрации пользователю анимации ожидания во время продолжительных запросов;
□ OnBegin — задает наименование JavaScript-функции, которая должна быть вызвана непосредственно перед отправкой асинхронного запроса на сервер;
□ Oncomplete — задает наименование JavaScript-функции, которая должна быть вызвана сразу после того, как запрос был завершен, и до того, как результат запроса был записан в элемент разметки. Не имеет значения, был ли завершен запрос удачно или нет, функция, указанная через Oncomplete, все равно будет вызвана. Данная функция будет вызвана до onFailure или onSuccess. Если требуется, чтобы результат не был записан в элемент разметки, то функция, указанная в Oncomplete, должна вернуть false;
□ OnFailure — задает наименование JavaScript-функции, которая должна быть вызвана в случае, когда асинхронный запрос завершился с ошибкой;
□ OnSuccess — задает наименование JavaScript-функции, которая должна быть вызвана в случае, когда асинхронный запрос завершился успешно;
□ updateTargetid — задает идентификатор элемента разметки, в который должен быть записан результат асинхронного запроса на сервер. Вместе с этим параметром может быть использован параметр InsertionMode, который указывает, каким именно способом должны быть записаны данные в элемент разметки;
□ url — устанавливает значение адреса сервера, куда следует отправить запрос. Свойство использовать не обязательно, когда класс AjaxOptions применяется в Ajax.BeginForm и Ajax.ActionLink, где действие и контроллер задают данные адреса. В случае если Url все же будет указан, он переопределит значения, определенные в этих методах.
Класс AjaxOptions и его свойства используются во вспомогательных методах Ajax.BeginForm и Ajax.ActionLink для тонкой настройки асинхронного запроса и его параметров, а также действий, осуществляемых в ответ на изменение состояния запроса. Например, в следующием фрагменте кода AjaxOptions используется для задания ряда параметров при вызове Ajax.ActionLink:
<p>
<script type="text/javascript">
function OnError() {
alert("Произошла ошибка!");
}
</script>
<%= Ajax.ActionLink("получить время", "GetTime", "Home",
new AjaxOptions() {
OnFailure="OnError",
Confirm="Bы уверены?",
UpdateTargetId = "timeText"
},
(object) null)
%><br/>
<span id="timeText">Нажмите на ссылку для получения времени<^span>
</p>
Вспомогательный метод Ajax.BeginForm, в зависимости от реализации, содержит набор из следующих параметров:
□ actionName — указывает наименование действия, которое следует вызвать в запросе, в случае, когда используется вариант метода без указания контроллера, вызывается действие контроллера текущего контекста;
□ controllerName — указывает наименование контроллера (сокращенное, без суффикса Controller), в котором следует искать и вызвать указанное в параметре actionName действие;
□ routeValues — указывает объект, содержащий параметры для механизма маршрутизации;
□ ajaxOptions — указывает экземпляр класса AjaxOptions с заданными свойствами, которые определяют параметры асинхронного запроса и могут определять ряд JavaScript-функций, реагирующих на изменение состояния запроса;
□ htmlAttributes — набор значений пользовательских атрибутов для тега form, которые должны быть помещены в разметку формы.
Ajax-расширения MVC Framework могут значительно облегчить работу по созданию Ajax-функционала как для форм, так и для простых запросов. Например, следующий код описывает создание простой Ajax-формы:
<% using(Aj ax.BeginForm("LoginForm",
new AjaxOptions{UpdateTargetId="loginStatus"})) {
%>
<dl>
<dt>
<span id="loginStatus">Введите логин и пароль, чтобы продолжить.</span>
</dt>
<dt>Введите логин:</dt>
<dd><%= Html.TextBox("login")%></dd>
<dt>Введите пароль:</dt>
<dd><%= Html.TextBox("password")%></dd>
<dt><input type="submit" value="Войти"/></dt>
</dl>
<% } %>
Здесь с помощью вспомогательного метода Ajax.BeginForm создается стандартная форма авторизации с двумя текстовыми полями для ввода логина и пароля и кнопкой отправки данных. Обратите внимание на параметры Ajax.BeginForm: во-первых, указывается LoginForm — наименование действия, которое должно вызваться в ответ на отправку данных с формы, во-вторых, с помощью класса AjaxOptions задается специальный параметр UpdateTargetId, который указывает на элемент, ответственный за отображение результата запроса. То есть, если запрос вернет данные, они будут отображены, в нашем случае, с помощью элемента span с идентификатором loginStatus.
Как можно заметить, создание всего Ajax-функционала не потребовало у нас ни строчки JavaScript, не требуется от нас и понимание различий реализаций поддержки Ajax разными браузерами. Все это скрытно реализуют библиотеки MicrosoftAjax.js и MicrosoftMvcAjax.js, делая за разработчика всю рутинную работу по организации работы с асинхронными запросами. Если мы взглянем на исходный код, который сгенерирует подсистема Ajax в MVC Framework для нашего кода, то сможем убедиться, что генерируется достаточно много автоматического кода. Далее представлено определение формы, которое создано автоматически для нашего примера:
<form action="/Home/LoginForm" method="post"
onclick="Sys.Mvc.AsyncForm.handleClick(this, new Sys.UI.DomEvent(event));"
onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this,
new Sys.UI.DomEvent(event), {
insertionMode:Sys.Mvc.InsertionMode.replace,
updateTargetId:'loginStatus'
});">
Как можно видеть, вызов Ajax.BeginForm сгенерировал код для функционала, который предлагают библиотеки MicrosoftAjax.js и MicrosoftMvcAjax.js.
Вспомогательный метод Ajax.ActionLink, в зависимости от реализации, содержит набор из нескольких следующих параметров:
□ linkText — текст, который будет рендериться в виде значения гиперссылки;
□ actionName — указывает наименование действия, которое следует вызвать в запросе, в случае, когда используется вариант метода без указания контроллера, вызывается действие контроллера текущего контекста;
□ controllerName — указывает наименование контроллера (сокращенное, без суффикса Controller), в котором следует искать и вызвать указанное в параметре actionName действие;
□ protocol — указывает используемый для формирования ссылки протокол http или https;
□ hostName — указывает значение хоста, которое будет использовано для формирования ссылки;
□ fragment — указывает значение якоря, которое будет использовано для формирования ссылки. Это значение используется браузером для навигации по странице и обычно представляет собой значение идентификатора какого-либо элемента разметки, к которому следует выполнить навигацию. Данное значение будет добавлено к ссылке в следующем виде: http://localhost/Home/GetTime#fragment;
□ routeValues — указывает объект, содержащий параметры для механизма маршрутизации;
□ ajaxOptions — указывает экземпляр класса AjaxOptions с заданными свойствами, которые определяют параметры асинхронного запроса и могут определять ряд JavaScript-функций, реагирующих на изменение состояния запроса;
□ htmlAttributes — набор значений пользовательских атрибутов для тега a, которые должны быть помещены в разметку формы.
Применение ActionLink еще проще, рассмотрим его использование на примере получения даты и времени для отображения на странице:
<%= Ajax.ActioriLink(''Пaлучить время", "GetTime", "Home",
new AjaxOptions() { UpdateTargetId = "timeText" },
(object) null) %><br />
<span id="timeText">Нажмите на ссылку для получения времени<sрап>
Здесь с помощью вспомогательного метода Ajax.ActionLink создается ссылка, которая с помощью Ajax.NET скрытно связывается с асинхронным запросом на сервер. Кроме текста ссылки, наименования действия и контроллера, в функцию передается набор параметров AjaxOptions, в котором, в нашем случае, параметр UpdateTargetId устанавливается равным идентификатору элемента, где будет отображен результат запроса. В последний параметр, который определяет значение атрибутов HTML-элемента, передается значение (object) null, чтобы указать, что никаких дополнительных HTML-атрибутов рендерить не нужно.
Как и в случае использования Ajax.BeginForm, при рендеринге Ajax.ActionLink незаметно для разработчика создается вспомогательный код, который реализует весь Ajax-функционал, избавляя разработчика от написания рутинного кода:
<a href="/Home/GetTime?Length=4"
onclick="Sys.Mvc.AsyncHyperlink.handleClick(this,
new Sys.UI.DomEvent(event),
{
insertionMode: Sys.Mvc.InsertionMode.replace, updateTargetId: 'timeText'
});">Получить время</a>
После того как пользователь нажмет на ссылку, сформируется асинхронный запрос на сервер, и полученный результат будет выведен в элемент span с идентификатором timeText.
Метод IsAjaxRequest является методом расширения для класса HttpRequestBase. Данный метод возвращает булево значение, которое сообщает, является ли текущй запрос Ajax-запросом или нет. IsAjaxRequest может быть полезен тогда, когда ваше действие меняет логику в зависимости от типа запроса. Например, в следующем примере представлена реализация действия, в котором в зависимости от типа запроса возвращается либо набор данных, либо данные с готовой HTML-разметкой:
public ActionResult GetTime()
{
if (Request.IsAjaxRequestO)
{
return Json(DateTime.Now.ToString());
} else
return View(DateTime.Now.ToString());
}