12

私はこのようなものを送る必要があります:

   <soapenv:Header>
      <ser:userName>admin</ser:userName>
      <ser:userPassword>secret</ser:userPassword>
   </soapenv:Header>

Delphi WSDL インポータは、これを生成しました:

  userName2 = class(TSOAPHeader)
  private
    FValue: string;
  published
    property Value: string  read FValue write FValue;
  end;

  userName      =  type string;

  WsService = interface(IInvokable)
    function call(const userName: userName; const userPassword: userPassword);

タイプを次のように登録しました。

  InvRegistry.RegisterHeaderClass(TypeInfo(WsService), userName2, 'userName', 'http://localhost/path/to/services');

問題は、デルファイで生成されたコードを使用して呼び出すと、 userName とパスワードが SOAP メッセージの Body セクションではなく、 Header に配置されることです。

そこで、次のようにヘッダーを自分で送信してみました。

ISOAPHeaders.Send() メソッドを使用して文字列を送信できないため、型定義を userName2 クラスから継承するように変更しました。

userName = class(userName2);        

次にヘッダーを送信しました:

user := userName.Create;
user.Value := 'admin';

WS := GetWsService;
(WS as ISOAPHeaders).Send(user);

これでヘッダーは正しい場所に配置されましたが、次のように送信されています。

<SOAP-ENV:Header>
    <NS1:userName xmlns:NS1="http://localhost/path/to/services">
        <Value xmlns="http://localhost/path/to/services">admin</Value>
    </NS1:userName>
</SOAP-ENV:Header>

ほとんどありますが、「Value」プロパティは必要ありません。ヘッダーに単純な単純なタグが必要なだけです

どうすればいいですか?

ありがとう。

==編集==

リクエストに応じて、WSDL は次の場所にあります: http://desenvolvimento.lemontech.com.br:8081/wsselfbooking/WsSelfBookingService?wsdl

SOAP UI がそれをインポートし、このサンプル リクエストを生成しました。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://lemontech.com.br/selfbooking/wsselfbooking/services">
   <soapenv:Header>
      <ser:userPassword></ser:userPassword>
      <ser:userName></ser:userName>
      <ser:keyClient></ser:keyClient>
   </soapenv:Header>
   <soapenv:Body>
      <ser:pesquisarSolicitacao>
         <!--You have a CHOICE of the next 2 items at this level-->
         <idSolicitacaoRef></idSolicitacaoRef>
         <dataInicial></dataInicial>
         <dataFinal></dataFinal>
         <registroInicial>1</registroInicial>
         <!--Optional:-->
         <quantidadeRegistros>50</quantidadeRegistros>
      </ser:pesquisarSolicitacao>
   </soapenv:Body>
</soapenv:Envelope>

このサンプル リクエストは問題なく動作しますが、Delphi でこの呼び出しを行う方法がわかりません。

4

3 に答える 3

9

任意のTSOAPHeaderクラスのシリアル化をオーバーライドできます。ObjectToSOAPその機能をオーバーライドするだけです。私はこれを思いついた:

unit Unit16;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, WsSelfBookingService, StdCtrls,
  InvokeRegistry, SOAPHTTPClient, opCOnvertOptions, XMLIntf, XSBuiltIns;

type
  TForm1 = class(TForm)
    Memo2: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
 TSOAPCredentials = class(TSoapHeader)
 private
    FPassword: string;
    FUsername: string;
    FKeyClient: string;
 public
   function ObjectToSOAP(RootNode, ParentNode: IXMLNode;
                            const ObjConverter: IObjConverter;
                            const NodeName, NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions;
                            out RefID: InvString): IXMLNode; override;
 published
   property userName     : string read FUsername write Fusername;
   property userPassword : string read FPassword write FPassword;
   property keyClient : string read FKeyClient write FKeyClient;
 end;



var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TSOAPCredentials }

function TSOAPCredentials.ObjectToSOAP(RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const NodeName,
  NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString): IXMLNode;
begin
 Result := ParentNode.AddChild('userName');
 Result.Text := FUsername;
 Result := ParentNode.AddChild('userPassword');
 Result.Text := FPassword;
 Result := ParentNode.AddChild('keyClient');
 Result.Text := FKeyClient;
end;

procedure TForm1.Button1Click(Sender: TObject);

var
 ws   : WsSelfBooking;
 Req  : pesquisarSolicitacao;
 Resp : pesquisarSolicitacaoResponse;
 Rio  : THTTPRIO;
 Cred : TSOAPCredentials;

begin
 Rio := THttpRIO.Create(nil);
 ws := GetWsSelfBooking(false, '', Rio);
 Cred := TSOAPCredentials.Create;
 Cred.userName := 'admin';
 Cred.userPassword := 'secret';
 Cred.keyClient := 'key';
 Rio.SOAPHeaders.Send(cred);
 Req := pesquisarSolicitacao.Create;
 Req.registroInicial := 1;
 Req.quantidadeRegistros := 50;
 Resp := ws.pesquisarSolicitacao(Req);    
end;

end.

このリクエスト ヘッダーは次のようになります。

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
 <SOAP-ENV:userName>admin</SOAP-ENV:userName>
 <SOAP-ENV:userPassword>secret</SOAP-ENV:userPassword>
 <SOAP-ENV:keyClient>key</SOAP-ENV:keyClient>
</SOAP-ENV:Header>
于 2012-12-11T15:16:22.937 に答える
8

解決:

あまり明白ではありませんでしたが、IS_TEXT値をIndexに追加し、新しい TSOAPHeader の子孫を宣言するだけで済みました。解決策は次のとおりです。

const
  IS_TEXT = $0020;

type
  TSimpleHeader = class(TSOAPHeader)
  private
    FValue: string;
  published
    property Value: string Index (IS_TEXT) read FValue write FValue;
  end;

  userName = class(TSimpleHeader);

次に、このヘッダーを登録します。

InvRegistry.RegisterHeaderClass(TypeInfo(WsService), userName, 'userName', 'http://localhost/path/to/services');

ヘッダーを手動で送信します。

    User := userName.Create;
    User.Value := 'username';

    (WS as ISOAPHeaders).Send(User);

基本的に、インデックス内の IS_TEXT 値により、Delphi はその中に userName タグと Value タグを作成できなくなります。Value プロパティの文字列を userName タグ内に配置するだけです。

Index キーワークがあまりにも明白ではないものに使用されているのは悲しいことです。また、それに関するドキュメントも見つけにくく、理解しにくいものです。

AS_ATTRIBUTE 機能は廃止されました。従来のコードでも機能しますが、推奨されるアプローチは、プロパティのインデックス値を使用することです。index プロパティを使用すると、プロパティが属性であるか、無制限の要素であるか、オプションの要素であるか、テキスト値であるか、NULL の値を持つことができるかを指定できます。

ソース: http://docwiki.embarcadero.com/RADStudio/XE3/en/Using_Remotable_Objects

于 2012-12-11T13:51:43.557 に答える
2

XML 文字列が「ネットワークに」送信される直前に、XML 文字列に stringreplace を使用してタグを挿入できます。RIO_BeforeExecute ハンドラーが必要で、SOAPRequest を直接処理できます。

于 2012-12-06T19:51:24.110 に答える