Введение в веб-сервисы
Мир Internet
Андрей Филёв
Многие уже знакомы с новой технологией компании Microsoft - .NET. Но далеко не все знают, что одним из первоначальных имен платформы .NET было NGWS (Next Generation Web Services), ведь новая технология позиционировалась как базовая для создания интернет-приложений нового типа - веб-сервисов. На поддержку и продвижение данной технологии компания Microsoft затратила огромные ресурсы, и эту инициативу подхватили многие гиганты индустрии, такие как IBM, Sun, Hewlett-Packard, SAP AG и другие.
В развитии стандартов новой технологии активное участие принимает World Wide Web Consortium (www.w3.org), более того, в связи с возросшим интересом к новой технологии консорциум недавно организовал группы Web Services Architecture, Web Services Description и Web Services Coordination.
С тем, что собой представляет одна из самых быстроразвивающихсясовременных интернет-технологий, вы сможете познакомиться в этой статье.
Андрей Филёв,
Михаил Плизкин
Веб-сервисы - это новый способ программного доступа к функциональности веб-серверов, в основе которого лежат два широко используемых стандарта - HTTP (используется в качестве протокола для передачи данных) и XML (используется в качестве способа представления самих данных). Для вызовов методов и передачи данных в сервисах используется протокол SOAP (Simple Object Access Protocol), для описания сервисов - язык WSDL (Web Service Description Language), а для структурирования, каталогизирования и поиска сервисов - служба UDDI (Universal Description, Discovery, and Integration).
Именно с помощью UDDI вы можете поместить сервис в каталог, где клиенты, работающие на серверах, настольных компьютерах и мобильных устройствах, динамически могут его обнаружить. Это открывает новые горизонты для предоставления программных услуг.
Но почему именно веб-сервисы?
Приложения и раньше обменивались информацией через Интернет - для этого служат DCOM-, CORBA-, Java RMI-, HTTP GET/POST-запросы. Все эти способы обладают одним или несколькими недостатками: уних отсутствует расширяемость, есть проблемы с доступом через сетевой экран, они привязаны к определенной платформе программирования, возникают сложности при разработке сервиса и клиентского приложения.
Типичные примеры - различные финансовые серверы выдают курсы валют и котировки по-разному, та же неразбериха с погодой, статистикой и другими данными, что заметно усложняет разработку b2b- (business-to-business)
систем и порождает сложные системы с доминированием связей "многие-ко-многим".
Кроме того, многие веб-мастера из-за сложности старых технологий и не задумывались о возможности написания программной функциональности для своих серверов. Тот, кто хотел иметь доступ к этой информации из своих программ, вынуждены были запрашивать HTML-код с помощью HTTP-запросов и затем производить его разбор, вычленяя нужные данные по частям.
Технологии, лежащие в основании веб-сервисов, помогают избавиться от перечисленных недостатков. Протокол HTTP является одним из самых распространенных, используемый им порт 80 чаще всего открыт на межсетевых экранах. Программные вызовы с использованием этого протокола в качестве носителя можно делать из любой среды, поддерживающей TCP/IP, а к ним относятся большинство современных сред программирования (Java, Perl, Win32, .NET).
Сообщения SOAP и документы WSDL представляют собой XML. А XML является стандартом де-факто для кроссплатформенного представления структурированной информации, библиотек, поддерживающих XML, нет разве что в древнейших манускриптных языках программирования.
В результате сервис, написанный на .NET, можно использовать в программе на Perl или Java. Разработка таких сервисов достаточно проста, поэтому постоянно создаются новые библиотеки, делающие работу с веб-сервисами все более простой и "родной" для той или иной среды разработки.
Рассмотрим в статье работу с веб-сервисами с использованием платформы Microsoft .NET, так как эта сравнительно недавно появившаяся среда программирования хорошо приспособлена для их создания.
SOAP
Знание SOAP не обязательно для работы с веб-сервисами, так что нетерпеливые читатели могут пропустить этот фрагмент. Тем не менее, знакомство с данным протоколом поможет вам глубже понять механизм работы веб-сервисов.
Структура сообщения SOAP очень проста - это XML-документ, помещенный в рамки HTTP-сообщения. SOAP определяет механизм передачи команд и параметров по HTTP вне зависимости от операционной системы, языка программирования или объектной модели на клиентской или серверной стороне. SOAP основан на наиболее распространенных интернет-технологиях и не требует специальных настроек маршрутизаторов, межсетевых экранов или прокси-серверов.
Ниже приведены примеры одного и того же запроса к веб-сервису, выполненного разными способами (SOAP, HTTP GET, HTTP POST).
SOAP
POST /webservices/usergroupservice.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: [здесь должна указываться длина]
SOAPAction: "http:// localhost/webservices/GetUserGroups"
<?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>
<GetUserGroups xmlns="http://localhost/webservices/"/>
</soap:Body>
</soap:Envelope>
HTTP GET
GET /webservices/usergroupservice.asmx/GetUserGroups?
е HTTP/1.1
Host: localhost
HTTP POST
POST /webservices/usergroupservice.asmx/GetUserGroups
е HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: [здесь должна указываться длина]
Остановимся на первом способе (SOAP-запрос). Первые четыре строчки - обычный POST-заголовок. Основной интерес для нас представляет включенный в тело запроса XML-документ. Его элементами являются <Envelope> и <Body>, в которые включен вызов метода GetUserGroups. Как видим, у этого метода нет параметров.
Вызов метода посложнее (со строковым аргументом) выглядит так:
<?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>
<FindUserGroupsByName
xmlns="http://www.dotsite.spb.ru/webservices/">
<name>string</name>
</FindUserGroupsByName>
</soap:Body>
</soap:Envelope>
Теперь давайте посмотрим, как мог бы выглядеть ответ на данный запрос:
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: [здесь должна указываться длина]
<?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>
<FindUserGroupsByNameResponse
xmlns="http://www.dotsite.spb.ru/webservices/">
<FindUserGroupsByNameResult>
<UserGroup>
<Name>string</Name>
<Mission>string</Mission>
<Country>string</Country>
<State>string</State>
<City>string</City>
<FoundationDate>dateTime</FoundationDate>
<Administrator>
<FirstName>string</FirstName>
<LastName>string</LastName>
<Email>string</Email>
<Password>string</Password>
<UserName>string</UserName>
<RoleName>string</RoleName>
<ID>int</ID>
<ICQ>string</ICQ>
</Administrator>
<ID>int</ID>
</UserGroup>
<UserGroup>
<Name>string</Name>
<Mission>string</Mission>
<Country>string</Country>
<State>string</State>
<City>string</City>
<FoundationDate>dateTime</FoundationDate>
<Administrator>
<FirstName>string</FirstName>
<LastName>string</LastName>
<Email>string</Email>
<Password>string</Password>
<UserName>string</UserName>
<RoleName>string</RoleName>
<ID>int</ID>
<ICQ>string</ICQ>
</Administrator>
<ID>int</ID>
</UserGroup>
</FindUserGroupsByNameResult>
</FindUserGroupsByNameResponse>
</soap:Body>
</soap:Envelope>
Синим цветом выделены поля, в которые будут подставлены значения соответствующего типа.
В оригинале (в программном коде самого сервиса) метод выглядел следующим образом:
[WebMethod (Description="Находит группы по названию")]
public UserGroup[] FindUserGroupsByName(string name) {
UserGroup[] groups =
UserGroup.GetUserGroupsFromDataSet
(UserGroup.GetUserGroupsByName(name));
foreach (UserGroup group in groups)
ServiceAccessChecker.CutHiddenData(group);
return groups;
}
Как видим, массив объектов в SOAP представляется достаточно просто - в виде последовательно расположенных соответствующих им XML-структур. Имена тегов в этих структурах соответствуют именам полей в объектах.
Приведенный выше сервис написан на языке C#. Рассмотрим более сложный пример для того, чтобы детально проиллюстрировать процесс создания веб-сервисов с помощью .NET.
WSDL
При разработке веб-приложений часто возникает проблема получения клиентом информации об услугах, предоставляемых веб-сервисом, и способах обращения к ним. Для решения этой проблемы фирмами Microsoft, IBM и Ariba был разработан язык описания веб-сервисов (Web Service Description Language, WSDL).
Отметим в первую очередь, что каждый документ WSDL является (по определению) документом XML. Эта особенность представляется очень логичной и удобной ввиду широкого распространения XML в качестве универсального формата хранения данных. Опишем вкратце структуру WSDL-документа (иногда называемого также контрактом; мы тоже будем использовать этот термин).
Контракт описывается в следующих терминах:
типы;
сообщения;
типы портов;
привязки;
порты;
сервисы.
В каждое из этих понятий вкладывается вполне определенный смысл. Приведем соответствующие определения:
Типы - это понятия, в терминах которых описываются сообщения.
Сообщения - это абстрактные представления передаваемых данных. Сообщения состоят из нескольких элементов, с каждым из которых связан некоторый тип данных в некоторой системе типов.
Типы портов - это наборы абстрактных операций, производимых с входящими и исходящими сообщениями.
Привязки определяют конкретные протокол и формат данных для операций, введенных конкретным типом порта.
Порты вводят адреса для привязок, определяя тем самым точку входа для внешних каналов связи.
Сервисы - это наборы взаимосвязанных портов.
Приведем примеры использования каждого из понятий. Мы постараемся описать контракт простейшего сервиса, который в ответ на запрос выдает некий ответ. Большинство веб-сервисов, которые разработчикам придется создавать на первых порах, будут, вероятно, организованы столь же просто или будут распадаться на несколько взаимодействующих веб-сервисов с аналогичным контрактом. При этом внутренняя структура может быть сколь угодно сложной, внешний же интерфейс может по-прежнему описываться достаточно просто.
<types>
<schema
targetNamespace="http://sitename.com/questionanswer.xsd"
xmlns="http://www.w3.org/1999/XMLSchema">
<element name="Request">
<complexType>
<all>
<element name="contents" type="int"/>
</all>
</complexType>
</element>
<element name="Response">
<complexType>
<all>
<element name="contents" type="float"/>
</all>
</complexType>
</element>
</schema>
</types>
На этом примере видно, как при помощи языка определения типа документа XML Schema определяются несколько новых типов данных (в нашем случае два).
<message name="RequestInformation">
<part name="body" element="xsd1:Request"/>
</message>
<message name="ReplyForRequest">
<part name="body" element="xsd1:Responce"/>
</message>
В этом фрагменте описаны два сообщения: первое представляет собой запрос на получение некой информации, а второе - ответ на этот запрос. Каждое из сообщений содержит некоторые данные с типами, определенными ранее.
<portType name="RequestResponcePortType">
<operation name="RequestResponceOperation">
<input message="tns:RequestInformation"/>
<output message="tns:ReplyForRequest"/>
</operation>
</portType>
Здесь представлено описание абстрактного порта, с которым можно производить единственную операцию: запросить цену товара. Эта операция состоит из получения входного сообщения и посылки ответа на него. Оба эти действия (для удобства разработчика) могут рассматриваться как единая операция.
<binding name="RequestResponceBinding"
type="tns:RequestResponcePortType">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="RequestResponceOperation">
<soap:operation soapAction=
е"http://sitename.com/RequestResponceOperation"/>
<input>
<soap:body use="literal" namespace=
е"http://sitename.com/questionanswer.xsd"
encodingStyle=
е"http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="literal"
еnamespace="http://sitename.com/questionanswer.xsd"
encodingStyle=
е"http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
Данный фрагмент описывает привязку типа порта к протоколу (в данном случае SOAP). Здесь определяется, как на уровне протокола должны осуществляться посылка и прием сообщений.
<service name="RequestResponceService">
<documentation>A sample service
<port name="RequestResponcePort"
binding="tns:RequestResponceBinding">
<soap:address location=
е"http://sitename.com/requestresponce"/>
</port>
</service>
И наконец, здесь определяются порт и сервис с кратким документирующим пояснением.
Обязательным элементом синтаксиса WSDL являются пространства имен XML. Это требование обусловлено расширяемостью WSDL, на основе которой строится поддержка различных физических протоколов (в частности, стандартно определены расширения для
SOAP 1.1, HTTP GET/POST и MIME). Расширяемость используется также для поддержки различных систем типов.
Некоторых дополнительных пояснений требует понятие типа порта. Тип порта - это набор связанных с ним абстрактных операций. Эти операции определяются в терминах посылаемых и принимаемых сообщений. Физические аспекты процесса приема и передачи при этом не затрагиваются. Используемые протоколы определяются в привязках, а конкретные адреса - в портах. Такое разделение необходимо прежде всего для реализации повторного использования фрагментов WSDL-документов.
В определениях привязок стандартно можно использовать ссылки на протоколы SOAP, HTTP GET/POST и MIME. Система типов может быть легко создана на основе XML Schema. Задача разработчика, таким образом, четко разделяется на части. Некоторые (а в идеале все) фазы генерации контракта могут быть выполнены машинным путем при создании веб-сервиса. Существующие приложения не поддерживают такую возможность, однако в перспективе этот процесс будет полностью автоматизирован.
Таким образом, документ WSDL полностью описывает интерфейс веб-сервиса со внешним миром. Единственной проблемой остается поиск веб-сервисов и их контрактов для решения конкретных задач.
Создание сервиса
В качестве примера создадим сервис, который будет выдавать список веб-мастеров абстрактного сайта. Для того чтобы показать гибкость сериализации объектов в XML, создадим сервис, возвращаемым значением которого будет массив объектов, полями которых станут массивы других объектов.
Предпожим, у вас уже стоит Visual Studio.NET и IIS версии 5 и выше. Запустим Visual Studio.NET, после чего выберем File Ґ New Ґ Project. Из списка проектных типов нужно выбрать ASP.NET Web Service, расположенный в группе Visual C# Projects. В качестве названия проекта введем любое удобное вам, например, webservices.
Теперь добавим нужный нам сервис. Для этого в Solution Explorer щелкнем правой кнопкой мыши на названии проекта, выберем Add Ґ Add Web Service и введем название файла SampleService.asmx.
После этого Visual Studio создаст файлы, необходимые для работы сервиса. Первый, SampleService.asmx, полностью делегирует реализацию всей функциональности C#-классу webservices.SampleService, который среда также автоматически сгенерировала в файле SampleService.asmx.cs.
Текст файла SampleService.asmx приведен ниже, и модифицировать его мы не будем:
<%@ WebService Language="c#" Codebehind="SampleService.asmx.cs" Class="webservices.SampleService" %>
А вот над C#-файлом придется поработать. Добавим в проект несколько C#-классов, в которых будут называться веб-мастера и описываться их способности:
public class WebMaster {
public string Name;
public Skill[] TechnologySkills;
public WebMaster() {
}
public WebMaster(string name, Skill[]
technologySkills) {
Name=name;
TechnologySkills=technologySkills;
}
}
public class Skill {
public string TechnologyName;
public int SkillAge;
public Skill() {
}
public Skill(string technologyName, int skillAge) {
TechnologyName=technologyName;
SkillAge=skillAge;
}
}
Обратите внимание на наличие пустых публичных конструкторов. Их описать необходимо для того, чтобы стала возможной сериализация/десериализация (преобразование структуры данных объекта в XML и наоборот).
Реализацию рабочего метода самого веб-сервиса сделаем максимально простой:
[WebMethod(Description="Получить список веб-мастеров")]
public WebMaster[] GetWebMasters() {
return (new WebMaster[] {
new WebMaster("Serge", new Skill[] {
new Skill("Java", 2)
}),
new WebMaster("Nick", new Skill[] {
new Skill(".NET",2)
})
});
}
Больше для создания сервиса нам не потребуется писать ни строчки кода!
После компиляции проекта (меню Build) наш веб-сервис будет доступен по адресу
http://localhost/webservices/SampleService.asmx
Более того, по адресу
http://localhost/webservices/SampleService.asmx?WSDL
можно посмотреть контракт нашего сервиса, а по адресу
http://localhost/webservices/SampleService.asmx?еop=GetWebMasters
даже запустить его вручную из браузера и увидеть примеры SOAP-, HTTP GET- и HTTP POST-запросов.
Ниже приведен полный С#-код нашего сервиса (SampleService.asmx.cs):
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
namespace webservices {
/// <summary>
/// Пример сервиса
/// </summary>
public class SampleService :
System.Web.Services.WebService {
[WebMethod(Description=
е"Получить список веб-мастеров")]
public WebMaster[] GetWebMasters() {
return (new WebMaster[] {
new WebMaster("Serge", new Skill[] {
new Skill("Java", 2)
}),
new WebMaster("Nick", new Skill[] {
new Skill(".NET", 2)
})
});
}
}
public class WebMaster {
public string Name;
public Skill[] TechnologySkills;
public WebMaster() {
}
public WebMaster(string name, Skill[]
technologySkills) {
Name=name;
TechnologySkills=technologySkills;
}
}
public class Skill {
public string TechnologyName;
public int SkillAge;
public Skill() {
}
public Skill(string technologyName, int skillAge) {
TechnologyName=technologyName;
SkillAge=skillAge;
}
}
}
Использование сервисов.
Добавим в наше решение новый проект (кликнем правой кнопкой на названии решения Ґ Add Ґ New Project Ґ Visual C# Projects/ConsoleApplication).
После этого добавим в этот проект ссылку на наш сервис. Для этого кликнем правой кнопкой на названии решения Ґ Add Web Reference, в поле Address введем адрес контракта нашего сервиса
http://localhost/webservices/SampleService.asmx?WSDL
после чего нажмем на кнопку Add Reference.
Несложный код нашего клиента будет выглядеть так:
namespace SampleServiceClient {
class Class1 {
[STAThread]
static void Main(string[] args)
{
localhost.SampleService sampleService =
new localhost.SampleService();
localhost.WebMaster[] webMasters =
sampleService.GetWebMasters();
foreach
(localhost.WebMaster webMaster in webMasters) {
Console.WriteLine(webMaster.Name);
}
}
}
}
А вывод на экран будет весьма предсказуемым:
Serge
Nick
Заключение
Итак, данная публикация познакомила вас с тем, что есть веб-сервис и для чего он нужен, рассказала о лежащих в основе сервисов технологиях и протоколах, а также показала, как можно быстро реализовать простой веб-сервис с помощью новейшей среды разработки Visual Studio.NET.
Перед вами открыто обширное поле для экспериментов: можно уже сейчас сделать часть вашего сайта доступной для любой из платформ и сред программирования.
Размеры публикации не позволили о многом рассказать. Новейшую информацию вы всегда можете получить по адресам www.w3.org (World Wide Web Consortium), msdn.microsoft.com/webservices (основной источник информации о построении веб-сервисов на базе .NET), www.dotsite.spb.ru (русскоязычный портал по разработке .NET-приложений). Вы можете также ознакомиться с работающими веб-сервисами и их исходным кодом на сайте www.dotsite.spb.ru.
Лучшие онлайн игры на деньги
|