在Delphi的SOAP Header中发送简单的字符串

时间:2012-12-06 19:44:48

标签: web-services delphi soap delphi-xe2

我需要发送这样的内容:

   <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');

问题是当我使用delphi生成的代码调用它时,它将userName和密码放在SOAP消息的Body部分中,而不是在Header中

所以我尝试自己发送标题,就像这样:

将类型定义更改为从userName2类继承,因为我无法使用ISOAPHeaders.Send()方法发送字符串。

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中进行此调用。

3 个答案:

答案 0 :(得分:8)

<强>解决方案:

这不是很明显,但我只需要将 IS_TEXT 值添加到索引并声明一个新的TSOAPHeader后代,解决方案是这样的:< / p>

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标记内。

令人遗憾的是,索引关键字用于不太明显的事情,而且关于它的文档很难找到并且难以理解:

  

不推荐使用AS_ATTRIBUTE功能。它仍适用于遗留代码,但首选方法是使用属性的索引值。 index属性允许您指定属性是属性,无界元素,可选元素,文本值,还是值为NULL。

来源:http://docwiki.embarcadero.com/RADStudio/XE3/en/Using_Remotable_Objects

答案 1 :(得分:7)

您可以覆盖任何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>

答案 2 :(得分:2)

您可以在XML字符串“走到电线上”之前使用XML字符串上的字符串替换来注入标记。您需要一个RIO_BeforeExecute处理程序,然后您可以直接处理SOAPRequest。