уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Давненько я собирался разобраться с протоколом SOAP, посмотреть как с ним работать, как использовать и т.д., но то за неимением большого количества свободного времени, то из-за обычного нежелания заморачиваться над чем-то новым всё никак не мог добраться до написания какого-нибудь приложения с использованием SOAP. Обычно, когда я разбирался с каким-либо API Web-сервиса у которого на выбор было два протокола – чистый HTTP или с SOAP я выбирался первый и, собственно сегодня понял, что зря :).

Оказалось, что разработать небольшой клиент с SOAP в Delphi элементарно и на порядок проще, чем использовать отдельно библиотеку для работы с HTTP (Synapse, WinInet, Indy и т.д.) в связке с библиотеками типа MSXML, NativeXML (для работы с XML) или SuperObject (для JSON).

В качестве примера я решил написать небольшой клиент для работы с Bing Translator API (переводчик Google уже был – теперь решил посмотреть, что там насочиняли в Microsoft).

Для начала несколько вводных слов по тому, что из себя представляет протокол SOAP.

Выписка из Wiki:

SOAP (от англ. Simple Object Access Protocol — простой протокол доступа к объектам) — протокол обмена структурированными сообщениями в распределённой вычислительной среде. Первоначально SOAP предназначался в основном для реализации удалённого вызова процедур (RPC). Сейчас протокол используется для обмена произвольными сообщениями в формате XML, а не только для вызова процедур.

На той же странице Wiki можно узнать и про недостаток SOAP – увеличение объема пересылаемых данных. Но нам сегодня это не так важно, нам бы просто разобраться с работой.

Примечание: Если же для вас очень важен объем пересылаемых данных, то можно привести следующую классификацию обмена данными в различных форматах (за исключением Plain Text) и с использованием различных протоколов (из тех, что мне сейчас более менее известны):

  1. HTTP + SOAP – наибольший объем;
  2. HTTP + XML – средний объем;
  3. HTTP + JSON – наименьший объем;

Все типы данных, операции, способы доставки сообщений от сервера к клиенту и обратно расположены на стороне сервера в виде WSDL-документа. Все, что от нас необходимо – это импортировать каким-либо образом этот документ и представить его в виде уже известных нам типов, классов и объектов Delphi.

Так как WSDL – это стандартный язык описания web-сервисов, то, соответственно, в Delphi предусмотрен удобный импорт таких документов и представление их в необходимой нам форме, т.е. в виде отдельного юнита Delphi.

Теперь перейдем непосредственно к рассмотрению примера работы с Bing API через SOAP.

Прежде, чем мы запустим Delphi и начнем разрабатывать наш мини-переводчик нам необходимо зарегистрироваться в Bing и на странице для разработчиков получить ключ доступа (AppID) к API. Регистрируемся, получаем и запоминаем наш AppID.

Теперь запускаем Delphi (у меня стоит Delphi XE) и выбираем в меню File –> New –> Other. В открывшемся окне выбираем WebServices –> WSDLImporter.

WSDLImporter  WSDLImporter представляет собой мастера, который максимально удобно и аккуратно импоритирует нам все методы, типы и классы сервиса нам в Delphi. Для начала мастер попросит нас ввести путь к WSDL-документу и, если это необходимо – данные для авторизации:

WSDLImporter2

Путь к WSDL-документу Bing Translator API указан на первой странице документации и выглядит следующим образом:

http://api.microsofttranslator.com/V2/Soap.svc

“Скармливаем” его мастеру и жмем “Next”:

WSDLImporter3

Мастер просит нас выбрать версию SOAP, которую мы будем использовать. Оставляем значение по умолчанию и жмем “Next”:

WSDLImporter4

Здесь мастер нас спросит какие опции WSDL нам необходимо импортировать. В принципе того, что выбрано по умолчанию нам вполне достаточно, поэтому со спокойной душой жмем “Finish” и мастер создает нам вполне понятный юнит с названием soap.pas. На этом работа с WSDLImporter заканчивается и приступаем к реализации функций переводчика.

Создаем обычное приложение (VCL Forms Application) и подключаем в uses только что созданный модуль soap.pas.

Бросаем также на форму компоненты TButton, TListBox и компонент THTTPRIO со страницы (WebServices).

Теперь открываем документацию по SOAP Bing API и попробуем реализовать несколько различных функций. Начнем с функций, возвращающих строки, например, воспользуемся методом Microsoft.Translator.Detect. Смотрим его описание в модуле SOAP.pas:

LanguageService = interface(IInvokable)
  ['{605B2735-9E5A-5D06-DFDA-8FBEA3B18556}']
    ...
    function  Detect(const appId: string; const text: string): string; stdcall;
    ...
  end;

 

Вызвать такой метод для нас намного проще и легче, чем скажем, использовать связку HTTP+XML — сначала сформировать URL, потом выполнить запрос и получить ответ, потом парсить XML и выводить результат. Но остается один вопрос: как собственно отправить этот самый запрос? Именно для этого мы и уложили на форму компонент THTTPRIO. Остается только его настроить следующим образом:

В поле WSDLLocation записываем тот же URL, что и при импорте WSDL-документа (см. выше) и в полях Port и Service выбираем единственные доступные значения. Должно получиться как показано на рисунке:

HTTPRIO

И теперь самое интересное – если вы посмотрите список методов компонента HTTPRIO, то не обнаружите в нем таких привычных при работе с HTTP методов как POST, GET и др. Они нам собственно и не нужны – у нас есть интерфейс LanguageService с помощью которого мы и получим необходимые нам данные.

Создаем обработчик OnClick кнопки и пишем:

ShowMessage((HTTPRIO1 as LanguageService).Detect('YouAppID','some text'))

 

Запускаем приложение, жмем кнопку и видим сообщение:

BingTranslator1

Запрос отправлен, ответ получен. Без парсинга XML и JSON и прочих обычных операций при работе с HTTP. Неправда ли достаточно просто и удобно? :). Со сложными типами данных так же просто работать, т.к. их описание содержится в модуле. Например, можно воспользоваться методом Microsoft.Translator.GetLanguageNames, который возвращает нам массив строк — названий языков на языке пользователя. Смотрим описание метода в soap.pas:

function  GetLanguageNames(const appId: string; const locale: string; const languageCodes: ArrayOfstring): ArrayOfstring; stdcall;

 

Единственный тип данных, который может быть нам непонятен — это ArrayOfString. Смотрим его описание в модуле:

ArrayOfstring = array of string;

 

Пишем обработчик кнопки. Например, так:

procedure TForm1.Button1Click(Sender: TObject);
var LangNames: ArrayOfstring;
    Names: ArrayOfstring;
    i:integer;
begin
 SetLength(LangNames,5);
 LangNames[0]:='fr';
 LangNames[1]:='en';
 LangNames[2]:='ru';
 LangNames[3]:='de';
 LangNames[4]:='ko';
 Names:=(HTTPRIO1 as LanguageService).GetLanguageNames('YouAppID','ru',LangNames);
 ListBox1.Items.Clear;
 for i:=0 to Length(Names)-1 do
   ListBox1.Items.Add(Names[i]);
end;

 

Запускаем программу, жмем кнопку и видим результат в ListBox:

BingTranslator2

Если в массиве LangNames будет содержаться “непонятная” серверу строка, то ошибки не возникнет, а результат работы метода будет содержать на 1 элемент меньше.

И, в заключение этой небольшой статьи, попробуем перевести какой-нибудь текст. Для этого воспользуемся методом Microsoft.Translator.GetTranslations, который возвращает нам все возможные переводы текста. Напишем такой обработчик у кнопки:

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
    Opt: TranslateOptions;
    Result : GetTranslationsResponse;
begin
  Opt:=TranslateOptions.Create;
  Result:=(HTTPRIO1 as LanguageService).GetTranslations('YouAppID','Memory','en','ru',10,Opt);
  for i:=0 to Length(Result.Translations)-1 do
      ListBox1.Items.Add(Result.Translations[i].TranslatedText)
end;

 

Результат выполнения программы будет следующим:

BingTranslator3

Вот, пожалуй и все. Думаю, что в качестве небольшой шпаргалки по работе с Bing API через SOAP в Delphi этот пост сгодится. Можете попрбовать поработать с API переводчика от Microsoft.

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
13 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Alexander
Alexander
24/06/2011 02:11

Здравствуйте ув. Автор!
Очень нужна Ваша помощь.
Мне нужно организовать общение с интернет магазинами на движке PrestaShop по REST протоколу. В частности отправлять данные в магазин. Здесь есть описание API: http://www.sendspace.com/file/6tqj4h
Пытался сделать WSDLImporter. В пути к WSDL-документу указал путь к api с учётом ключа, как описано в документации: http://TNP0ETIYA2KY6RU387GKKWJNSUX8OT94@prestashop2/api/
но в ответ получаю ошибку 401.
Помогите разобраться в моей проблеме. Я ещё пока не силён в REST.

Taron
Taron
11/07/2011 12:53

Добрый день.
 

procedure TForm1.Button1Click(Sender: TObject);
var LangNames: ArrayOfstring;
Names: ArrayOfstring;
i:integer;
begin
SetLength(LangNames,5);
LangNames[0]:=’fr’;
LangNames[1]:=’en’;
LangNames[2]:=’ru’;
LangNames[3]:=’de’;
LangNames[4]:=’ko’;
Names:=(HTTPRIO1 as LanguageService).GetLanguageNames(‘YouAppID’,’ru’,LangNames);
ListBox1.Items.Clear;
for i:=0 to Length(Names)-1 do
ListBox1.Items.Add(Names[i]);
end;
Возникает runtime ошибка
«Value cannot be null.Parameter name: languageCodes»

Горный Оптимизатор
Горный Оптимизатор
23/10/2011 15:48

Здравствуйте!
Выложите пожалуйста soap.pas, а то у меня WSDL Importer не пашет а Гугл молчит по всем (что только смог придумать) вариантам решения данного затруднения.

Горный Оптимизатор
Горный Оптимизатор
25/10/2011 01:33

Уже не надо, импортнул, но не проверял работу.
Там где показан импортер у вас на сайте у меня тоже есть такая иконка, только она не активная… и естественно он не запускается.
По чистой случайности нашел данный импортер по другому адресу: Component -> Import WSDL

tintintin
tintintin
16/03/2012 13:43

Поддерживаю Taron:
Тоже, возникает runtime ошибка«Value cannot be null.Parameter name: languageCodes»
Притом  LangNames может быть действительно пустым, или получен через GetLanguagesForTranslate, или как в примере — результат один — ошибка. Остальные методы, куда НЕ передаётся тип ArrayOfString работают корректно. Такое ощущение, что динамический массив всегда определяется как пустой и на сервис передаётся null вместо нормального массива. Интересно, что при этом GetLanguagesForTranslate заполняет динамический массив корректно, но это не вход, а выход )

tintintin
tintintin
16/03/2012 14:18

Ошибка решилась очень «экстравагантным методом» ))
Под Delphi 2010 — ошибка есть, под Delphi XE2U3  — ошибки нет ))
Embarcadero, лучше поздно, чем никогда )) 

arankar
arankar
04/04/2012 09:17

Почему этот пример не работает на Delphi2009 а на Delphi XE2 работает? Не только этот пример даже если сам написал SOAP  сервер клиент написанный на Delphi2009 не работает! 

bega
bega
12/04/2012 23:14

oshibka
 
Result:=(HTTPRIO1 as LanguageService).GetTranslations(‘YouAppID’,’Memory’,’en’,’ru’,10,Opt)
 
 
 
Dcc error: incompatible types ‘getTranslationsResponse’ and ‘getTranslationsResponse2’
 

ShrecK
ShrecK
08/05/2012 03:04

Спасибо за статью, реально просто выручила, столько мучился, а тут прям как раз нашел разъяснение всех интересующих нюансов. Еще раз спасибо!

halilpro
01/08/2012 16:08

А как при реализации веб-сервиса в функции определить обязательный/необязательный параметр?

SOAP
SOAP
09/03/2013 01:24

Ограничение: 2 млн. символов в месяц.
Пруфф