Родительские члены-потомки TRemotable не включены в WSDL, созданный веб-службами delphi - PullRequest
1 голос
/ 04 июня 2010

В прошлом я создавал Web-сервисы с Delphi, но большинство из них были довольно простыми, просто принимали несколько параметров и возвращали одно значение клиенту. Новая услуга, над которой я работаю, требует, чтобы я мог отправлять и получать сложные типы. Учтите, что в моем коде определены следующие типы:

TBaseRequest = Class(TRemotable)
  private
    FUsername: string;
    FPassword: string;
  published
    Property Username: String read FUsername write FUsername;
    Property Password: String read FPassword write FPassword;
End;

TBaseResponse = Class(TRemotable)
  private
    FStatusMessage: string;
    FStatusCode: integer;
  published
    Property StatusMessage: string read FStatusMessage write FStatusMessage;
    Property StatusCode: integer read FStatusCode write FStatusCode;
End;

TSepecialRequest = class(TBaseRequest)
private
  FExtraParam: string;
published
  Property ExtraParam: String read FExtraParam write FExtraParam;
end;

TSpecialResponse = class(TBaseResponse)
private
  FExtraResult: string;
published
  Property ExtraResult: String read FExtraResultwrite FExtraResult;
end;

Все эти классы зарегистрированы в RemClassRegistry.RegisterXSClass.

Теперь у меня также есть следующая функция, определенная в интерфейсе для этого веб-сервиса:

function SpecialMethod(request:TSepecialRequest): TSpecialResponse;

В сервисном коде я могу легко получить доступ к свойствам родительского класса, таким как Имя пользователя и Пароль, но если мы посмотрим на сгенерированный WSDL, то увидим, что члены класса TSpecialRequest и TSpecialResponse включены в раздел схемы.

  <xs:complexType name="TSpecialRequest">
    <xs:complexContent>
      <xs:extension base="TBaseRequest">
        <xs:sequence>
          <xs:element name="ExtraParam" type="xs:string"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>
  <xs:complexType name="TSpecialResponse">
    <xs:complexContent>
      <xs:extension base="TBaseResponse">
        <xs:sequence>
          <xs:element name="ExtraResult" type="xs:string"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

Этот фрагмент схемы в WSDL показывает, что TSpecials являются расширениями классов TBase, и все хорошо, за исключением того, что описание схемы TBase не включено в схему. Я ожидаю, что также будет такой раздел, но он отсутствует:

  <xs:complexType name="TBaseRequest">
    <xs:sequence>
      <xs:element name="Username" type="xs:string"/>
      <xs:element name="Password" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="TBaseResponse">
    <xs:sequence>
      <xs:element name="StatusMessage" type="xs:string"/>
      <xs:element name="StatusCode" type="xs:int"/>
    </xs:sequence>
  </xs:complexType>

Однако этот фрагмент схемы отсутствует в сгенерированном WSDL. Это означает, что любой клиент, пытающийся использовать эту службу, не сможет правильно генерировать запросы или интерпретировать ответы. Например, если я попытаюсь загрузить сгенерированный WSDL в импортер WSDL в Delphi 2009, я получу следующие классы:

TSpecialRequest = class(TRemotable)
private
  FExtraParam: WideString;
published
  property ExtraParam: WideString read FExtraParam write FExtraParam;
end;

TSpecialResponse = class(TRemotable)
private
  FStatusMessage: WideString;
  FStatusCode: Integer;
published
  property StatusMessag: WideString read FStatusMessage write FStatusMessage;
  property StatusCode: Integer read FStatusCode write FStatusCode;
end;

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

Кто-нибудь знает, почему это происходит или что я могу с этим сделать?

Ответы [ 2 ]

1 голос
/ 18 марта 2011

Delphi генерирует схему только для классов, на которые есть прямые ссылки в интерфейсе веб-службы. В идеале он должен включать базовые классы обратно в TRemotable, но это не так.

Я обнаружил, однако, что если вы добавите фиктивный метод в интерфейс с базовыми классами в списке параметров, Delphi сгенерирует недостающие определения. Например:

procedure BaseClasses(BaseRequest: TBaseRequest; BaseResponse: TBaseResponse); stdcall;

Это определенно хак, и немного раздражает необходимость выставлять такой метод, но он выполняет то, что вы хотите.

Я знаю, что этот ответ немного запоздал для вас, но, возможно, он пригодится кому-то еще в будущем.

1 голос
/ 10 июня 2010

Я не думаю, что получу ответ, но я нашел работу вокруг. Я не очень доволен этим, но это помогает мне решить проблему. Симптом, описанный выше, можно избежать, используя состав объекта вместо наследования. Этот код работает, как и ожидалось, но он менее прост в использовании. Полагаю, я захочу придумать какую-то фабрику сообщений в моей реализации, но это выходит за рамки темы.

Это решение может быть проиллюстрировано следующим кодом:

TBaseRequest = Class(TRemotable)
  private
    FUsername: string;
    FPassword: string;
  published
    Property Username: String read FUsername write FUsername;
    Property Password: String read FPassword write FPassword;
end;

TSepecialRequest = class(TRemotable)
private
  FExtraParam: string;
  FBaseRequest: TBaseRequest;
published
  Property ExtraParam: String read FExtraParam write FExtraParam;
  Property BaseRequest: TBaseRequest read FBaseRequest write FBaseRequest;
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...