Общие сведения о веб-службах ASP.NET AJAX

Скотт Кейт

Веб-службы являются неотъемлемой частью платформы .NET, которая предоставляет кроссплатформенное решение для обмена данными между распределенными системами. Хотя веб-службы обычно используются для разрешения различных операционных систем, объектных моделей и языков программирования для отправки и получения данных, они также могут использоваться для динамического внедрения данных на страницу AJAX ASP.NET или отправки данных с страницы в серверную систему. Все это можно сделать, не прибегая к операциям возврата данных.

Вызов веб-служб с помощью ASP.NET AJAX

Дэн Валин (Dan Wahlin)

Веб-службы являются неотъемлемой частью платформы .NET, которая предоставляет кроссплатформенное решение для обмена данными между распределенными системами. Хотя веб-службы обычно используются для разрешения различных операционных систем, объектных моделей и языков программирования для отправки и получения данных, они также могут использоваться для динамического внедрения данных на страницу AJAX ASP.NET или отправки данных с страницы в серверную систему. Все это можно сделать, не прибегая к операциям постбэк.

Хотя элемент управления UpdatePanel в ASP.NET AJAX предоставляет простой способ добавить AJAX-функциональность на любую страницу ASP.NET, иногда необходимо динамически обращаться к данным на сервере без использования UpdatePanel. В этой статье вы узнаете, как это сделать, создавая и потребляя веб-службы на ASP.NET страницах AJAX.

В этой статье рассматриваются функциональные возможности, доступные в основных расширениях ASP.NET AJAX, а также элемент управления с поддержкой веб-службы в наборе средств ASP.NET AJAX, называемый AutoCompleteExtender. В этой статье рассматриваются определение веб-служб с поддержкой AJAX, создание прокси-серверов клиента и вызов веб-служб с помощью JavaScript. Кроме того, вы увидите, как вызовы веб-сервисов можно выполнять непосредственно к методам страниц ASP.NET.

Конфигурация веб-служб

При создании нового проекта веб-сайта в Visual Studio 2008 файл web.config имеет ряд новых дополнений, которые могут быть незнакомы пользователям предыдущих версий Visual Studio. Некоторые из этих изменений сопоставляют префикс asp с ASP.NET элементами управления AJAX, чтобы они могли использоваться на страницах, а другие определяют необходимые httpHandlers и HttpModules. В списке 1 показаны изменения, внесенные в элемент <httpHandlers> в web.config, которые влияют на вызовы веб-службы. По умолчанию HttpHandler, используемый для обработки вызовов ASMX, удаляется и заменяется классом ScriptHandlerFactory, расположенным в сборке System.Web.Extensions.dll. System.Web.Extensions.dll содержит все основные функции, используемые ASP.NET AJAX.

Список 1. настройка обработчика веб-службы ASP.NET AJAX

<httpHandlers>
     <remove verb="*" path="*.asmx"/>
     <add verb="*" path="*.asmx" validate="false"
          type="System.Web.Script.Services.ScriptHandlerFactory,
          System.Web.Extensions, Version=1.0.61025.0, Culture=neutral,
          PublicKeyToken=31bf3856ad364e35"/>
</httpHandlers>

Эта замена HttpHandler выполняется для разрешения вызовов нотации объектов JavaScript (JSON) из ASP.NET страниц AJAX в веб-службы .NET с помощью прокси-сервера веб-службы JavaScript. ASP.NET AJAX отправляет сообщения JSON в веб-службы в отличие от стандартных вызовов протокола SOAP, которые обычно связаны с веб-службами. Это приводит к уменьшению числа сообщений запросов и ответов в целом. Кроме того, он позволяет более эффективно обрабатывать данные на стороне клиента, так как библиотека JavaScript ASP.NET AJAX оптимизирована для работы с объектами JSON. В списке 2 и листинге 3 показаны примеры сообщений запроса и ответа веб-службы, сериализованных в формат JSON. Сообщение запроса, показанное в списке 2, передает параметр страны со значением "Бельгия", а ответное сообщение в списке 3 передает массив объектов Customer и их связанных свойств.

Перечисление 2. Сериализованное в JSON сообщение запроса веб-службы

{"country":"Belgium"}

> [! ПРИМЕЧАНИЕ] Имя операции определяется как часть URL-адреса веб-службы; Кроме того, сообщения запросов не всегда отправляются через JSON. Веб-службы могут использовать атрибут ScriptMethod с параметром UseHttpGet, равным true, что приводит к передаче параметров строки запроса.

Список 3. Сообщение ответа веб-службы сериализовано в JSON

[{"__type":"Model.Customer","Country":"Belgium","CompanyName":"Maison
     Dewey","CustomerID":"MAISD","ContactName":"Catherine
     Dewey"},{"__type":"Model.Customer","Country":"Belgium","CompanyName":"Suprêmes
     délices","CustomerID":"SUPRD","ContactName":"Pascale
     Cartrain"}]

В следующем разделе вы узнаете, как создавать веб-службы, способные обрабатывать сообщения запроса JSON и отвечать на них как с простыми, так и сложными типами.

Создание веб-служб с поддержкой AJAX

Платформа AJAX ASP.NET предоставляет несколько различных способов вызова веб-служб. Вы можете использовать элемент управления AutoCompleteExtender (доступный в наборе средств AJAX ASP.NET) или JavaScript. Однако, прежде чем вызывать службу, необходимо её настроить для работы с AJAX, чтобы можно было вызвать её клиентским скриптом.

Независимо от того, знакомы вы или нет с веб-службами ASP.NET, вам будет просто создать и включить службы с поддержкой AJAX. Платформа .NET поддерживает создание веб-служб ASP.NET с момента его первоначального выпуска в 2002 году, а расширения AJAX ASP.NET предоставляют дополнительные функциональные возможности AJAX, которые создаются на основе набора функций платформы .NET Framework по умолчанию. Visual Studio .NET 2008 Beta 2 имеет встроенную поддержку создания файлов веб-сервисов .asmx и автоматически генерирует связанный код на основе классов, производных от System.Web.Services.WebService. При добавлении методов в класс необходимо применить атрибут WebMethod для их вызова потребителями веб-службы.

В описании 4 показан пример применения атрибута WebMethod к методу GetCustomersByCountry().

Перечисление 4. Использование атрибута WebMethod в веб-службе

[WebMethod]
public Customer[] GetCustomersByCountry(string country)
{
     return Biz.BAL.GetCustomersByCountry(country);
}

Метод GetCustomersByCountry() принимает параметр страны и возвращает массив объектов Customer. Значение страны, передаваемое в метод, пересылается в класс бизнес-слоя, который, в свою очередь, вызывает класс слоя данных для получения данных из базы данных, заполняет свойства объекта Customer данными и возвращает массив.

Использование атрибута ScriptService

При добавлении атрибута WebMethod метод GetCustomersByCountry() может быть вызван клиентами, отправляющими стандартные SOAP сообщения в веб-сервис, но он не позволяет выполнять вызовы JSON из ASP.NET AJAX приложений без дополнительной настройки. Чтобы разрешить вызовы JSON, необходимо применить атрибут расширения AJAX ScriptService ASP.NET к классу веб-службы. Это позволяет веб-службе отправлять сообщения ответа, отформатированные с помощью JSON, и позволяет клиентскому скрипту вызывать службу, отправляя сообщения JSON.

В описании 5 показан пример применения атрибута ScriptService к классу веб-службы с именем CustomersService.

Список 5. Использование атрибута ScriptService для подключения веб-службы с помощью AJAX

[System.Web.Script.Services.ScriptService]
[WebService(Namespace = "http://xmlforasp.net")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CustomersService : System.Web.Services.WebService
{
     [WebMethod]
     public Customer[] GetCustomersByCountry(string country)
     {
          return Biz.BAL.GetCustomersByCountry(country);
     }
}

Атрибут ScriptService выступает в качестве маркера, указывающего, что его можно вызвать из кода скрипта AJAX. Он фактически не обрабатывает какие-либо задачи сериализации или десериализации JSON, которые происходят за кулисами. ScriptHandlerFactory (настроенный в web.config) и другие связанные классы выполняют большую часть обработки JSON.

Использование атрибута ScriptMethod

Атрибут ScriptService является единственным атрибутом ASP.NET AJAX, который должен быть определен в веб-службе .NET, чтобы он использовался ASP.NET страницами AJAX. Однако другой атрибут с именем ScriptMethod также можно применять непосредственно к веб-методам в службе. ScriptMethod определяет три свойства, включая UseHttpGetResponseFormat и XmlSerializeString. Изменение значений этих свойств может быть полезно в случаях, когда тип запроса, принятый веб-методом, необходимо изменить на GET, если веб-метод должен возвращать необработанные XML-данные в виде XmlDocument или объекте или XmlElement когда данные, возвращаемые из службы, всегда должны быть сериализованы как XML вместо JSON.

Свойство UseHttpGet можно использовать, если веб-метод должен принимать запросы GET, а не запросы POST. Запросы отправляются с помощью URL-адреса с входными параметрами веб-метода, преобразованными в параметры QueryString. Свойство UseHttpGet по умолчанию имеет значение false и должно быть задано true только в том случае, если операции, как известно, являются безопасными и когда конфиденциальные данные не передаются в веб-службу. В списке 6 показан пример использования атрибута ScriptMethod со свойством UseHttpGet.

Список 6. Использование атрибута ScriptMethod со свойством UseHttpGet.

[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public string HttpGetEcho(string input)
{
     return input;
}

Ниже показаны примеры заголовков, отправленных при вызове веб-метода HttpGetEcho, показанного в списке 6:

GET /CustomerViewer/DemoService.asmx/HttpGetEcho?input=%22Input Value%22 HTTP/1.1

Помимо разрешения веб-методов принимать HTTP-запросы GET, атрибут ScriptMethod также можно использовать, если xml-ответы необходимо возвращать из службы, а не JSON. Например, веб-служба может получить RSS-канал из удаленного сайта и вернуть его в виде объекта XmlDocument или XmlElement. Обработка XML-данных может происходить на клиенте.

В списке 7 показан пример использования свойства ResponseFormat для указания того, что XML-данные должны быть возвращены из веб-метода.

Листинг 7. Использование атрибута ScriptMethod со свойством ResponseFormat.

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml)]
public XmlElement GetRssFeed(string url)
{
     XmlDocument doc = new XmlDocument();
     doc.Load(url);
     return doc.DocumentElement;
}

Свойство ResponseFormat также можно использовать вместе со свойством XmlSerializeString. Свойство XmlSerializeString имеет значение false по умолчанию, что означает, что все типы возвращаемых значений, кроме строк, возвращаемых из веб-метода, сериализуются в формате XML, если ResponseFormat для свойства задано значение ResponseFormat.Xml. Если у XmlSerializeString установлено значение true, все типы, возвращаемые из веб-метода, включая строковые типы, сериализуются в формате XML. Если свойство ResponseFormat имеет значение ResponseFormat.Json, свойство XmlSerializeString игнорируется.

В описании 8 показан пример использования свойства XmlSerializeString для принудительной сериализации строк в формате XML.

Листинг 8. Использование атрибута ScriptMethod со свойством XmlSerializeString

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Xml,XmlSerializeString=true)]
public string GetXmlString(string input)
{
     return input;
}

Значение, возвращаемое из вызова веб-метода GetXmlString, показанного в списке 8, отображается следующим образом:

<?xml version="1.0"?>
     <string>Test</string>

Хотя формат JSON по умолчанию сводит к минимуму общий размер сообщений запроса и ответа и становится более легко потребляемым клиентами AJAX в ASP.NET в нескольких браузерах, свойства ResponseFormat и XmlSerializeString можно использовать, когда клиентские приложения, такие как Internet Explorer 5 или выше, ожидают, что XML-данные будут возвращаться из веб-метода.

Работа со сложными типами

В листинге 5 показан пример возврата сложного типа данных под названием Customer из веб-службы. Класс Customer определяет несколько различных простых типов внутри себя как свойства, такие как FirstName и LastName. Сложные типы, используемые в качестве входного параметра или возвращаемого типа в веб-методе с поддержкой AJAX, автоматически сериализуются в JSON перед отправкой на стороне клиента. Однако вложенные сложные типы (определенные внутри другого типа) по умолчанию недоступны клиенту в качестве автономных объектов.

В случаях, когда вложенный сложный тип, используемый веб-службой, также должен использоваться на клиентской странице, атрибут ASP.NET AJAX GenerateScriptType можно добавить в веб-службу. Например, класс CustomerDetails, показанный в списке 9, содержит свойства Address и Gender, представляющие вложенные сложные типы.

Листинг 9. Класс CustomerDetails, показанный здесь, содержит два вложенных сложных типа.

public class CustomerDetails : Customer
{
     public CustomerDetails()
     {
     }
     Address _Address;
     Gender _Gender = Gender.Unknown;
     public Address Address
     {
          get { return _Address; }
          set { _Address = value; }
     }
     public Gender Gender
     {
          get { return _Gender; }
          set { _Gender = value; }
     }
}

Объекты Address и Gender, определенные в классе CustomerDetails, показанном в листинге 9, не будут автоматически доступны для использования на стороне клиента через JavaScript, так как они являются вложенными типами (Адрес является классом и полом является перечислением). В ситуациях, когда вложенный тип, используемый в веб-службе, должен быть доступен на стороне клиента, атрибут GenerateScriptType, упомянутый выше, можно использовать (см. описание 10). Этот атрибут можно добавить несколько раз в тех случаях, когда из службы возвращаются различные вложенные сложные типы. Его можно применять непосредственно к классу веб-службы или выше определенных веб-методов.

Листинг 10. Использование атрибута GenerateScriptService для определения вложенных типов, которые должны быть доступны клиенту.

[System.Web.Script.Services.ScriptService]
[System.Web.Script.Services.GenerateScriptType(typeof(Address))]
[System.Web.Script.Services.GenerateScriptType(typeof(Gender))]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class NestedComplexTypeService : System.Web.Services.WebService
{
     //Web Methods
}

Применив атрибут GenerateScriptType к веб-службе, типы Address и Gender будут автоматически доступны для использования AJAX JavaScript кодом на стороне клиента ASP.NET. Пример JavaScript, который автоматически создается и отправляется клиенту путем добавления атрибута GenerateScriptType в веб-службе, показан в списке 11. Далее в статье вы узнаете, как использовать вложенные сложные типы.

Листинг 11. Вложенные сложные типы, доступные на странице ASP.NET AJAX.

if (typeof(Model.Address) === 'undefined')
{
     Model.Address=gtc("Model.Address");
     Model.Address.registerClass('Model.Address');
}
Model.Gender = function() { throw Error.invalidOperation(); }
Model.Gender.prototype = {Unknown: 0,Male: 1,Female: 2}
Model.Gender.registerEnum('Model.Gender', true);

Теперь, когда вы узнали, как создавать веб-службы и сделать их доступными для ASP.NET страниц AJAX, давайте рассмотрим, как создавать и использовать прокси JavaScript, чтобы получить или отправить данные в веб-службы.

Создание прокси-серверов JavaScript

Вызов стандартной веб-службы (.NET или другой платформы) обычно включает создание прокси-объекта, который защищает вас от сложностей отправки сообщений запроса и ответа SOAP. При вызовах веб-служб ASP.NET AJAX можно создавать и использовать JavaScript-прокси для легкого вызова служб, не беспокоясь о сериализации и десериализации сообщений JSON. Прокси-серверы JavaScript можно создавать автоматически с помощью элемента управления ASP.NET AJAX ScriptManager.

Создание прокси-сервера JavaScript, который может вызывать веб-службы, выполняется с помощью свойства Служб ScriptManager. Это свойство позволяет определить одну или несколько служб, которые страница AJAX ASP.NET может вызывать асинхронно для отправки или получения данных, не требуя операций обратной передачи. Вы определяете службу с помощью элемента управления ASP.NET AJAX ServiceReference и назначения URL-адреса веб-службы свойству элемента управления Path . В описании 12 показан пример ссылки на службу с именем CustomersService.asmx.

<asp:ScriptManager ID="ScriptManager1" runat="server">
     <Services>
          <asp:ServiceReference Path="~/CustomersService.asmx" />
     </Services>
</asp:ScriptManager>

Список 12. Определение веб-службы, используемой на странице ASP.NET AJAX.

Добавление ссылки на CustomersService.asmx через элемент управления ScriptManager приводит к динамическому созданию JavaScript-прокси, который затем используется на странице. Прокси-сервер внедряется с помощью <тега скрипта> и динамически загружается путем вызова файла CustomersService.asmx и добавления /js в конец файла. В следующем примере показано, как прокси-сервер JavaScript внедрен на страницу при отключении отладки в web.config:

<script src="CustomersService.asmx/js" type="text/javascript"></script>

> [! ПРИМЕЧАНИЕ. Если вы хотите увидеть фактический код прокси-сервера JavaScript, созданный, можно ввести URL-адрес нужной веб-службы .NET в поле адреса Internet Explorer и добавить /js в конец его.

Если отладка включена в web.config, то в страницу будет внедрена отладочная версия прокси-сервера JavaScript, как показано ниже:

<script src="CustomersService.asmx/jsdebug" type="text/javascript"></script>

Прокси JavaScript, который создает ScriptManager, также можно встраивать непосредственно в страницу, а не использовать с атрибутом src тега