Pull to refresh

Интеграция AJAX в ASP.NET MVC 4

Reading time 6 min
Views 80K
Наверное, уже не существует веб разработчика, который не слышал о Ajax. Microsoft в такой ситуации не может оставаться в стороне, с каждым релизом старается облегчить жизнь именно нам, ASP.NET MVC разработчикам. Но прежде чем я продолжу статью, немного отступлюсь от темы.

Когда я познакомился с MVC фреймворком, он был тогда только во второй версии и, столкнувшись с такими хелперами как @Ajax...., честно говоря, их реализация на стороне клиента меня не впечатлила. Нет, так нет, подумал я про себя, у меня есть jQuery со своим $.ajax, мне его за глаза. Вот и забыл я про них на несколько лет, к своему великому сожалению проморгав этот момент с третьим релизом. Что было, то было. Благо что взялся за ум и почитал две книги по MVC 4. Далее расскажу, как можно сократить написание строк кода благодаря хелперам, упомянутым мною выше.

Начну с того, что MVC может работать с двумя вариантами Ajax библиотек (конечно я же имею ввиду с коробки, не более того) — jQuery и Microsoft Ajax. Чтобы знать, для какого адаптера создавать разметку, существует настройка в web.config UnobtrusiveJavaScriptEnabled и соответствующее значение true (для работы с jQuery) и false (для работы с Microsoft Ajax). Если же нам необходимо поменять значение только для одного представления, можно воспользоваться методом — @{Html.EnableUnobtrusiveJavaScript(bool);}. Хочу обратить внимание, что данная настройка влияет и на формирование валидационных данных на стороне клиента.


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

<script src="~/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="~/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>

, a для jQuery

<script src="~/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>

Как я писал выше, вариант с jQuery меня вполне устраивает. Поэтому пойду по пути ненавязчивого JavaScript (т.е. web.config с />), и начну с самого простого.

ActionLink


Рассмотрим такую задачу. Есть ссылочка, при клике на которую мы хотим обновить содержимое контейнера. Что делал я ранее.

Кусочек метода действия

public ActionResult Index()
{
	if (Request.IsAjaxRequest())
		return PartialView("_IndexPartial");

	return View();
}

Index преставление

<script type="text/javascript">
	 jQuery(function($) {
	 	$('#update-container').click(function(e) {
	 		e.preventDefault();

	 		$.ajax({
	 			url: '@Url.Action("Index", "Home")',
	 			success: function(data) {
	 				$('#container').html(data);
	 			}
	 		});
	 	})
	 })
 </script>

<div id="container">
	@Html.Partial("_IndexPartial")
</div>

@Html.ActionLink("Поменять данные", "Index", "Home", new {}, new {id = "update-container"})

_IndexPartial частичное представление

<div>Динамическое данные в зависимости от запроса</div>

Большинству знаком такой вспомогательный метод как Html. ActionLink(...), представленный выше. Казалось бы, строк кода в принципе не много, да и привык так уже программировать, так что все в порядке, но ведь я очень ленивый программист и в меру своих сил борюсь за чистоту и уменьшение кода. Поэтому мне будет приятно уменьшить представление с 22 строк до 5. И на помощь ко мне приходит Ajax.ActionLink(...) (конечно, скептики могут сказать, что вместо $.ajax можно было использовать .load или $.get, но сути это не меняет, мы сократили представление, которое и так порой у нас начинает пухнуть)

Вуаля, Index преставление

<div id="container">
	@Html.Partial("_IndexPartial")
</div>

@Ajax.ActionLink("Поменять данные", "Index", "Home", new {}, new AjaxOptions{UpdateTargetId = "container"}, new {id = "update-container"}) //id элемента нам уже не нужно, но для наглядности оставлю

Разница между двумя расширенными методами Html.ActionLink и Ajax.ActionLink заключается только в одном параметре, объекте AjaxOptions. Давайте о нем и поговорим.

AjaxOptions




Как видно свойств, в принципе, у него не много, с другой стороны это и хорошо, когда начинают создавать серебряную пулю, будь то объект или библиотека, становится просто не вероятно громоздкой и неработоспособной.

Что из свойств за что отвечает, лучше MSDN я сказать не смогу.



Давайте пробежимся по свойствам:

Confirm — аналог javascript confirm(...)

HttpMethod — типа string, самое интересное, что же MS заставило ограничиться только 2 методами, ума не приложу почему, и видимо алгоритм таков, все что не GET, null или пустая строка после .Trim() — все POST

InsertionMode — перечисление со значениями "InsertAfter" (вставить в конец контейнера), "InsertBefore" (вставить в начало контейнера) или "Replace" (заменить содержимое контейнера)

Loading... — изначальный скрытый элемент

On..... — javascript функции, по аналогии с $.ajax
  • OnBeginbeforeSend
  • OnCompletecomplete
  • OnFailureerror
  • OnSuccesssuccess

Url — ссылка на отдельный адрес ajax запроса, если нам необходимо развести запрос от ajax запроса по разным роутам/контроллерам/действиям/параметрам (нужное подчеркнуть)

Ajax вспомогательные методы


Под конец хотелось бы привести табличку методов, которые нам время от времени облегчат нашу жизнь
Ajax.ActionLink Создает гиперссылку на действие контроллера, которая при нажатии отправляет запрос Ajax.
Ajax.RouteLink Похож на Ajax.ActionLink, но создает ссылку на определенный роут, а не действие контроллера
Ajax.BeginForm Создает элемент формы, который будет отправлять введенные данные к определенному действию контроллера
Ajax.BeginRouteForm Похож на Ajax.BeginForm, но отправляет запрос по определенному роуту, а не к действию контроллера
Ajax.GlobalizationScript Создает ссылку на скрипт глобализации, в котором содержится информация о языке и региональных параметрах
Ajax.JavaScriptStringEncode Кодирует строку для безопасного использования в JavaScript

Обеспечение постепенного ухудшения


Рассмотрим такую ситуацию. Ajax запрос возвращает JSON/XML/Частичное представление — и все хорошо, но такой подход совсем не приемлем, если пользователь отключил JavaScript, либо браузер вообще не поддерживает его. В таких случаях необходимо полностью вернуть страницу пользователю. Одним из решений является вариант использования «разводки» в одном методе действия с определением того, является ли этот запрос запросом Ajax. Это можно сделать, используя Request.IsAjaxRequest(), как было рассмотрено выше.

Вторым вариантом решения проблемы является создание двух разных методов действия: одного — для Ajax запроса, а второго — для обычного. Давайте рассмотрим этот вариант подробнее, на упрощенной задаче сохранения полученного от пользователя комментария.

Создаем два метода действия

[HttpPost]
public ActionResult AddComment(string comment)
{
	//необходимые действия
	return View();
}

[HttpPost]
public ActionResult AddCommentAjax(string comment)
{
	//необходимые действия
	return Json(new {resultMessage = "Ваш комментарий добавлен успешно!"});
}


представление AddComment

<h3>Ваш комментарий добавлен успешно!</h3>

и наше представление с формой

<script type="text/javascript">
	function OnSuccessComment(data) {
		alert(data.resultMessage);
	}
</script>

@using (Ajax.BeginForm("AddComment", new AjaxOptions
	                                     {
		                                   Url = Url.Action("AddCommentAjax"),
		                                   OnSuccess = "OnSuccessComment",
		                                   HttpMethod = "POST"
	                                     }))
{
	@Html.TextArea("comment")
	<input type="submit" value="Добавить комментарий"/>
}

Как это работает

Для браузера рендерится следующая форма

<form id="comment-form" action="/Home/AddComment" method="POST" data-ajax-url="/Home/AddCommentAjax" data-ajax-success="OnSuccessComment" data-ajax-method="POST" data-ajax="true">
	<textarea rows="2" name="comment" id="comment" cols="20"></textarea>
	<input type="submit" value="Добавить комментарий">
</form>

Мы видим, что отличие от @using (Html.BeginForm("AddComment", "Home")) заключается только в дополнительных data- атрибутах. Иными словами, для отключенного Javascript форма будет отравляться на public ActionResult AddComment(string comment). Когда же JavaScript включен, адаптер считывает данные с data- атрибутов, перехватывает отправку формы и делает запрос на public ActionResult AddCommentAjax(string comment). Успешный результат мы получаем в виде переданного JSON и обрабатываем в указанной js функции OnSuccessComment.

Резюме


Целью моей статьи было лишь показать, что некоторые вещи можно немного ускорить и не изобретать велосипед (сужу лишь по себе).



На написание этой статьи меня сподвигли главы книг:
Ajax в ASP.NET MVC (ASP.NET MVC 4 в действии)
и
Вспомогательные методы для URL и Ajax (pro ASP.NET MVC 4)




Tags:
Hubs:
+11
Comments 3
Comments Comments 3

Articles