我需要发送这样的内容:
<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中进行此调用。
答案 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。