Пережеванные выкладки программиста

или же трудные будни ленивца-скурпулезы

Previous Entry Share Next Entry
Быстрая реализация SOAP-клиента в Ebmbarcadero C++ Builder XE3
mylogo, xydan, xydan83_logo
xydan
Недавно появилась задачка реализовать общение одной клиентской программки по SOAP протоколу с сервером для запуска удаленных функций. В Builder есть несколько компонентов, с помощью которых можно реализовать протокол как со стороны сервера, так и клиента. Задача усложнилась тем, что сервер написан на Visual C++ где есть свои компоненты реализации Soap, а поскольку это Microsoft, то был поставлен вопрос совместимости вариантов данного протокола с реализации протокола в Builder компонентах (насколько я знаю, у них могут отличаться заголовки протокола, что уже может вызвать несовместимость реализации протокола на стандартных компонентах).
Забегая вперед скажу, что тут все обошлось, и клиент и сервер  нормально заработали друг с другом))

Почему решил написать статейку, потому, что долго искал информацию, как же быстро реализовать возможности клиента по SOAP общению с сервером. В интернете почему то очень мало информации на эту тему. Много пишут про сам протокол, а практического ликбеза к сожалению почти нет. В итоге  я начал реализовывать клиента через стандартный компонент TSoapConnection, но он позволяет только подключаться к серверу, а не вызывать удаленно функции.
В итоге собрал таки по крупицам инфу. Оказывается, чтобы реализовать клиента SOAP нужно всего несколько действий, которые я опишу тут (код тоже будет приведен).

Начну с того, что в билдере есть такая замечательная штука, как WSDL Importer, она позволяет сформировать уже готовый интерфейс (.cpp, .h) с помощью которого можно нативно вызывать удаленные функции по SOAP протоколу, как будто они выполняются у Вас на клиенте.
Так же поясню, что следующие действия будут касаться "статической линковки".
Собственно сами действия:
1) Нам понадобится .wsdl файл, который обычно генерируется на сервере, по сути это .xml с soap содержимым (структура). Файл с расширением .asmx так же подойдет (по сути тот же wsdl). Скопируйте этот файл к себе в проект, если это asmx то переименуйте расширение в .wsdl.
2)Далее File-->New-->Other вкладка WebServices-->WSDL Importer. В поле Location Source указываем путь к нашему файлу, так же можно ввести данные аутентификации. Жмем Next, затем выбираем версию протокола или оставляем по умолчанию на автомате, Next. Выставляем необходимые опции или так же оставляем по умолчанию и жмем Finish. Происходит генерация интерфейса, файлы автоматический добавятся в проект.
3)Кидаем на форму компонент HTTPRIO. (На самом деле его можно и не кидать на форму, он автоматический будет создан в функции модуля веб сервиса, который нам сгенерировал билдер, в случае, если мы не передадим в функцию указатель на свой компонент HTTPRIO).
4)По умолчанию, сгенерированный модуль называется WebService1.cpp(.h), пространство имен - NS_WebService1, а наша главная функция (та, что даст нам интерфейс) - GetWebService1Soap. Собственно кроме этой функции нам больше ничего не понадобится из этого модуля.
А теперь самое главное, функция GetWebService1Soap возвращает интерфейс в виде шаблонного класса DelphiInterface, а в качестве параметра шаблона идет наш класс, с функциями которые реализованы на сервере, они обозначаются у нас как абстрактные (собственно и весь класс параметра шаблона идет как абстрактный).  Называется этот класс по умолчанию WebService1Soap, соответственно возвращаемый тип будет как
typedef DelphiInterface<WebService1Soap> _di_WebService1Soap;
Дальнейшие действия которые мы должны сделать - это получить наш объект интерфейса, через который мы будем вызывать удаленные функции.
Пример кода:
_di_WebService1Soap ws = GetWebService1Soap(false, "http://127.0.0.1:7321/serv/WebService1.asmx", HTTPRIO1);
if(!ws)
{
ShowMessage("Объект _di_WebService1Soap не создан");
Application->Terminate();
}

Разберем параметры:
Если вы посмотрите на реализацию функции в файле WebService1.cpp, то можно увидеть константные значения настроек, они используются в зависимости от того, какие параметры мы передаем в функцию.
GetWebService1Soap - первый параметр типа bool, он указывает функции либо использовать в качестве wsdl удаленный файл по URL при false, либо использовать локальный файл при значении true;
Второй параметр - сам адрес URL (первый параметр должен быть false), либо путь к локальному файлу .wsdl (первый параметр должен быть true);
Третий параметр - это тот самый указатель на объект HTTPRIO. Соответственно, если передать в функцию NULL, то он будет создан автоматический, но я для наглядности все-таки сам разместил компонент на форме и передал на него указатель).
5)По сути все готово)) Теперь мы можем использовать удаленный вызов, как нативный, для этого мы используем объект (в моем случае) ws->имя удаленной функции.
6)И последнее, для удаления объекта из памяти (в случае если вы создаете его не на стеке), используем метод Release();

Собственно, на этом все) Если что не понятно, пишите вопросы в комментариях.

?

Log in