Недавно у меня возникла необходимость динамически подгружать пользовательские контролы на страницу. Это довольно просто реализовывается с помощью UpdatePanel. Но мне этот вариант не подошел, так как страница должна весить как можно меньше и работать как можно быстрее. Поэтому выбор пал именно на связку ASP.NET и JQuery + Web Service. Для начала давайте разберемся каким образом можно вызвать Web Method с помощью JQuery.
function getJsonAjaxObject(webServiceURL, jsonData) {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: serviceURL,
data: jsonData,
success:
function(msg){
//код обработки успешного вызова веб-метода
},
error:
function(XMLHttpRequest, textStatus, errorThrown){
//код обработки ошибки выполнения веб-метода
}
});
}
Из всего множества методов (load, get, post, getJSON, ajax) я выбрал именно ajax т.к. этот метод позволяет наиболее полно контролировать процесс создания асинхронного запроса к веб-сервису.
| Имя |
Тип |
Описание параметра |
| type |
string |
возможные варианты – GET или POST. Если параметр упущен, то по умолчанию будет использоваться метод GET. Типы запроса PUT или DELETE тоже могут быть использованы, но они поддерживаются не всеми браузерами. |
| contentType |
string |
при передаче данных серверу сообщает content-type. По умолчанию - application/x-www-form-urlencoded. |
| url |
string |
адрес веб-сервиса. Например, http://mysite.com/myservice.asmx/mywebmethod |
| data |
object |
данные, передаваемые на сервер. Добавляются в URL GET-запроса. Если используется объект, он должен представлять собой пары ключ/значение. Если значения представлены в виде массива, jQuery сериализует значения с некоторым ключом. Например: {foo:["bar1", "bar2"]} будет представлено как "&foo=bar1&foo=bar2". |
| success |
function |
указывается функция, которая будет вызвана в случае успешного завершения запроса. Функция принимает два аргумента: данные, возвращенные с сервера и отформатированные с учетом параметра dataType и строка, описывающая статус ответа(в нашем примере это строка всегда будет “success”). |
| error |
function |
определяет функцию, которая будет вызвана в случае неуспешного выполнения запроса. |
| dataType |
string |
строка, описывает тип данных, которые ожидаются в качестве ответа сервера. Если не определена, то jQuery сам попытается определить тип, основываясь на MIME-типе ответа сервера. Доступные типы: - xml: вернет XML документ, который может быть обработан через jQuery. - html: вернет HTML как plain text. - script: расценивает ответ как JavaScript и возвращает его как plain text. - json: расценивает ответ как данные в формате JSON и возвращает JavaScript объект. - jsonp: загружает данные в формате JSON используя JSONP. Необходимо дополнительно добавить "?callback=?" в конец строки запроса в URL, чтобы определить вызов. (Добавлено в jQuery 1.2). - text: строка plain text.
|
| async |
boolean
|
по умолчанию все запросы выполняются в асинхронном режиме (значение true). Если необходимо выполнить синхронный запрос, следует установить значение false для этой опции. Помните, что синхронный запрос может временно заблокировать браузер, запретив любые действия во время выполнения запроса. |
| beforeSend |
function
|
может содержать функцию, которая должна быть вызвана до передачи запроса. beforeSend - это Ajax Event (события рассмотрены в другой статье). |
| cache |
boolean
|
опция добавлена в jQuery 1.2. По умолчанию - true. Если установить в false, запрашиваемая страница не будет кэшироваться браузером. |
| complete |
function
|
определяет функцию, которая будет вызвана по окончанию запроса (успешного и ошибочного выполнения). Принимает два аргумента: объект XMLHttpRequest и строку, описывающую "успешность" запроса. complete - это Ajax Event (события рассмотрены в другой статье). |
| global |
boolean
|
true или false. Вызывать или нет глобальные обработчики событий Ajax для этого запроса. Может быть использована для контроля различных Ajax событий. По умолчанию - true. |
| ifModified |
boolean
|
запрос будет успешным только в случае, если данные ответа изменились со времени последнего запроса. По умолчанию - false. |
| processData |
boolean
|
по умолчанию true. В опции data данные представлены в виде объекта, который преобразуется в строку запроса, подходящую для content-type по умолчанию - "application/x-www-form-urlencoded". Если необходимо иное, установите опцию processData в false. |
| timeout |
number
|
устанавливает локальный тайм-аут для запроса в миллисекундах. Отменяет глобальный тайм-аут для этого запроса, если тот определен через $.ajaxSetup |
Необходимо также учесть, что ASP.NET Ajax enabled веб-сервис разрешает только HTTP POST (по умолчанию) для вызова метода, который возвращает JSON.
В большинстве случаев IIS 6 и выше требует наличия content-length элемента в запросе POST, даже если данных в запросе нет. Content-length для запроса без данных должен быть равен 0, но JQuery, в таком случае, этот элемент не добавляет. Поэтому для readonly запросов POST необходимо указывать пустой JSON объект:
data: “{}”
Это натолкнет JQuery на мысль указать корректный content-length и ваш веб-сервис сможет правильно распознать readonly-запрос, отбросив при этом пустой параметр.
Хочу еще обратить ваше внимание на то, что contentType установлен в "application/json;charset=utf-8". Этого требует ASP.NET AJAX. JSON-запросы, не имеющие подобного заголовка будут проигнорированы ASP.NET.
Еще одна проблема, с которой мне пришлось столкнуться, это “Maximum length exceed” ошибка. Она возникает в случае, когда длина JSON-ответа превышает длину по умолчанию. Во избежание этой ошибки необходимо добавить в web.config следующее:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="5000000" />
</webServices>
</scripting>
</system.web.extensions>
Вот так выглядит код моей страницы
<%@ Page Language="C#" EnableViewState="false" %>
<!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="head" runat="server">
<title>Add ASP.NET User Control dynamically with JQuery</title>
<script language="javascript" type="text/javascript" src="Scripts/jquery-1.2.6.pack.js"></script>
<style type="text/css">
body
{
width:95%;
padding-left:20px;
font-family:Arial;
font-size:10pt;
padding-right:20px;
}
</style>
</head>
<body>
<form id="form" runat="server">
<input type="button" value="Load GridView" onclick="getData('ScriptService.asmx/GetControlHtml','~/Controls/GridView.ascx');" />
<input type="button" value="Load Login Control" onclick="getData('ScriptService.asmx/GetControlHtml','~/Controls/LoginControl.ascx');" />
<div id="testDiv"></div>
</form>
<script type="text/javascript">
…
</script>
</body>
</html>
JavaScript для вызова веб-метода и динамического добавления пользовательского контрола на страницу
function getData(serviceURL, controlLocation) {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
url: serviceURL,
data: "{'controlLocation':'" + controlLocation + "'}",
success:
function(msg){
$('#testDiv').html(msg.d);
},
error:
function(XMLHttpRequest, textStatus, errorThrown){
alert( "Error Occured!" );
}
});
}
Для товарищей, малознакомых с JQuery (к коим отношусь пока и я), хочу
объяснить следующую строку javascript-кода
$('#testDiv').html(msg.d);
Собственно в этой строке и происходит все чудо, а именно нам возвращается
некий JSON-объект (msg), содержащий в себе строку. Часть строки $(‘#testDiv’)
вернет нам набор объектов с id=’testDiv’ (в нашем случае это будет один div),
далее мы вызываем метод html, который превратит нашу строку в дерево объектов и
поместит его в коллекцию дочерних элементов нашего div’a. Эту операцию можно
было записать несколько иначе:
$("#someElement")[0].innerHTML = msg.d;
Возможно, такая запись для кого-то будет понятней.
Данный пример доступен для скачивания. Исходные коды на C#.