#web-services #delphi #interface #runtime
#веб-службы #delphi #интерфейс #время выполнения
Вопрос:
Я создал веб-службу в Delphi XE с помощью WSDL importer. Delphi сгенерировал для меня модуль ITransmitter1.pas с интерфейсом ITransmitter и функцией GetITransmitter.
Для использования веб-сервиса я использую:
var Transmitter: ITransmitter;
begin
Transmitter := GetITransmitter(True, '', nil);
Transmitter.Transmit(Memo1.Text, OutXML);
end;
Но я нигде не вижу тела метода Transmit …
В ITransmitter.pas я вижу:
InvRegistry.RegisterInterface(TypeInfo(ITransmitter), 'urn:TransmitterIntf-ITransmitter', 'utf-8');
InvRegistry.RegisterDefaultSOAPAction(TypeInfo(ITransmitter), 'urn:TransmitterIntf-ITransmitter#Transmit');
Если я прокомментирую эти строки, я получу ошибку «интерфейс не поддерживается».
Как я вижу здесь, delphi добавляет метод во время выполнения !
Как это работает? Могу ли я добавить метод во время выполнения в свой собственный класс?
Ответ №1:
Если вы создали клиент веб-службы с помощью импортера WSDL, сгенерированный клиентский код вызовет метод на сервере. Таким образом, фактически, «тело» метода (код) находится на сервере веб-службы.
Delphi генерирует Soap-запрос на основе WSDL, а за кулисами RTTI (самоанализ) используется для генерации параметров и т.д. вызова веб-службы в виде XML. Этот XML отправляется на сервер, который выполняет реализацию метода и отправляет обратно ответ Soap.
Все наоборот, если вы создаете сервер веб-службы, в этом случае приложение Delphi, конечно, должно реализовать все тела методов.
Комментарии:
1. Я не могу отладить свой передатчик. Метод передачи. И мне все еще интересно, какой метод на самом деле выполняется, когда я вызываю Transmitter. Передавать? Обычно, когда я вызываю какой-либо метод, я вижу код, помещенный в какой-нибудь файл .pas. Теперь я понятия не имею, что на самом деле происходит, когда я вызываю этот метод …
Ответ №2:
Фактически вы вызываете метод, определенный в интерфейсе, который, в свою очередь, наследуется от IInvokable, объявленного в System.pas.
Если вы проверите свой исходный код, вы заметите, что ни один локальный объект в вашем проекте не реализует вызываемый вами интерфейс IInvokable, это потому, что этот метод выполняется удаленно на сервере.
Прежде чем это произойдет, есть некоторый код pascal, используемый для создания надлежащего SOAP-запроса к серверу, отправки его, а затем ожидания и интерпретации ответа сервера, рассмотрим детали этой реализации. Если вам интересно узнать немного больше о том, как это работает, включите опцию компилятора «использовать debug .dcus», чтобы вы могли выполнять отладку внутри VCL / RTL.
Затем, как обычно, используйте команду StepInto (F7), чтобы попросить отладчик выполнить метод передачи шаг за шагом … после некоторого ассемблера в тройке.Методом GenericStub вы перейдете к ТРИО.Универсальный метод, при котором пакет подготавливается и отправляется.
Для привязки btSOAP, которую я использую для написания этого ответа, соответствующая часть начинается со строки 943 в блоке Rio.pas:
try
FWebNode.Execute(Req, Resp);
finally
{ Clear Outbound headers }
FHeadersOutBound.Clear;
end;
THTTPReqResp.Execute затем использует wininet.dll функции для выполнения соединения, отправки и получения информации с использованием сервера.
Есть несколько уровней, на которых вы можете углубиться в это… как далеко вы хотите зайти, будет зависеть от ваших интересов, а большое количество деталей выходит далеко за рамки моего ответа здесь … не стесняйтесь публиковать больше вопросов с конкретными интересующими вас вопросами.
Я не уверен, но детали могут меняться в зависимости от версий Delphi… Прямо сейчас я использую Delphi XE.
Комментарии:
1. ОК. Что я вижу: объект Transmitter был сгенерирован функцией GetITTransmitter. Эта функция генерирует результат следующим образом: RIO := THTTPRIO. Create(nil); Результат := (RIO как ITransmitter); Таким образом, повторная реализация метода Transmit должна быть в классе THTTPRIO. Но, как я вижу, такого нет. Итак, насколько я понимаю, всякий раз, когда я вызываю любой метод Transmitter, неважно, какой, на самом деле TRIO. Будет выполнен GenericStub. Итак, могу ли я создать свой собственный класс с этим future? Я имею в виду такой класс, поэтому независимо от того, какой метод я вызываю, в любом случае delphi вызовет какой-то фиксированный метод ?
2. @Astronavigator: ITransmitter — это интерфейс, сгенерированный Delphi при обработке WDSL импортером WDSL. Короче говоря, универсальный метод вызывается для любого вызываемого вами метода интерфейса. На стороне клиента нет реального объекта, в котором этот метод определен: интерфейс определен для вашего удобства, вы можете взаимодействовать с веб-службой так же, как и с другими объектами в вашем приложении. Классы THTTPRio / TRio используют стандартный метод QueryInterface, который вызывается, когда оператор AS приводит объект к интерфейсу, чтобы сгенерировать VTable «на лету» для выполнения этого сопоставления.
3. Взгляните на метод TRio.GenVTable, который вызывается при обработке QueryInterface. Модуль — soap Rio.pas