我正在尝试实现一个 SOAP 客户端来处理由以下位置的 WSDL 文件描述的 Web 服务的加州工资税电子报告:FSET Service。在此 WSDL 文件中,引用了多个模式,其中包括http://schemas.xmlsoap.org/ws/2004/08/addressing中的一个模式,该模式似乎在程序到达 OnBeforeExecute 事件之前就将其停止。
为了开始这个项目,我尝试访问WSDL 文件中声明的Ping函数。
我现在刚刚获得一些在 Delphi 中创建 SOAP 客户端的经验。我正在使用 Delphi 2010。这是我为达到这一点所做的事情。我使用 WSDL 导入器导入上述地址的文件。它为我创建了一个名为 fsetservice 的单元。然后,我向项目添加了一个表单,并在其中添加了 HTTPRIO 组件。我将组件的 WSDLLocation 设置为 WSDL 文件的本地副本,在表单上放置几个 TMemos 以捕获请求和响应标头,并添加代码来执行此操作。然后我设置了一个按钮,并在其 OnClick 事件中编写了以下代码:
procedure TForm1.Button1Click(Sender: TObject);
var sResponse: String;
begin
sResponse := GetFsetServiceSoap.Ping;
end;
Run Code Online (Sandbox Code Playgroud)
当我单击该按钮时,在到达 HTTPRIO OnBeforeExecute 事件中的断点之前收到此消息:
标头http://schemas.xmlsoap.org/ws/2004/08/addressing:需要最终收件人的操作,但未出现在消息中
我知道我们每个帖子应该只问一个问题,但有时您的了解不够,无法只问一个好问题:
编辑:为了节省其他有相同问题的人的时间,我将我找到的答案放在这些问题下。
看起来 HTTPRIO 组件可能正在根据 WSDL 中引用的模式检查从 WSDL 文件导入的 XML 的完整性。这看起来很酷,但这是真的吗?
*答案:不正确,至少根据http://www.tutorialspoint.com/wsdl/wsdl_definition.htm页面底部的注释。根据注释,该模式不必实际存在于该位置,它只需唯一标识 WSDL 中使用的模式即可。*
在自动创建(且未修改)的 GetFsetService 函数中,我可以一直单步执行到最后,并且错误发生在返回时,似乎不可能单步进入调用错误的实际过程。有没有办法做到我所缺少的?
回答:我仍然不确定这一点,但似乎答案是否定的。无论如何,尽管从头开始编写此代码会更加乏味,但这比等待 WSDL 向导出现奇迹是一个更好的解决方案。
我是否错过了一些内容,说我需要实现为我自动创建的 FsetService 接口?
答:显然不是。
我在 Marco Cantu 的《Mastering Delphi 2005》一书中看到,Borland 提供了一个应用程序 (WebAppDbg.exe),它允许您查看在特定端口上发送的 HTTP。我尝试过但没有结果。这会有帮助吗?如果有的话,我应该使用哪个端口?
答案:使用 Fiddler2 工具。不错的发现。
我该如何克服这个错误?
答:用手做。
首先,在处理肥皂和 Web 服务时,我将首先将 Fiddler2 和 SoapUI 添加到您的工具库中。
听起来信封标题不完整。根据我使用 D2007 和 WCF Web 服务的经验,Delphi 无法正确构建信封标头,因此我必须拦截调用并添加如下项目:
procedure TMainForm.MyMessageEnvelopeComplete(Sender: TROSOAPMessage);
begin
Sender.EnvelopeNode.AddAttribute('xmlns:a', 'http://www.w3.org/2005/08/addressing', False);
Sender.HeaderNode.Add('a:Action').Value := 'http://Testservice.Connect/IConnect/Ping';
Sender.HeaderNode.Add('a:To').Value := 'http://testservice-pc:2021/WSConnect';
end;
Run Code Online (Sandbox Code Playgroud)
编辑:
如果您想手动构建肥皂信封和 post 命令,我已经使用以下代码完成了...
procedure TMainForm.Button5Click(Sender: TObject);
procedure HandleError(const errorCode: integer);
var
errorMessage: AnsiString;
begin
SetLength(errorMessage, 256);
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_FROM_HMODULE,
Pointer(GetModuleHandle('wininet.dll')),
errorCode, 0, PChar(errorMessage), Length(errorMessage), nil);
SetLength(errorMessage, StrLen(PChar(errorMessage)));
raise Exception.Create(errorMessage);
end;
function BuildHeader: TStringStream;
begin
result := TStringStream.Create('');
try
result.WriteString('Content-Type: application/soap+xml;charset=UTF-8;action="http://Thermo.Connect/IHCSConnect/Ping"' + sLineBreak);
except
result.Free;
raise;
end;
end;
function BuildBody: TStringStream;
begin
result := TStringStream.Create('');
with result do
try
WriteString('<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">' + sLineBreak);
WriteString('<s:Header>' + sLineBreak);
WriteString('<a:Action>http://Thermo.Connect/IHCSConnect/Ping</a:Action>' + sLineBreak);
WriteString('<a:To>http://thermo-pc:2021/WSHCSConnect</a:To>' + sLineBreak);
WriteString('</s:Header>' + sLineBreak);
WriteString('<s:Body>' + sLineBreak);
WriteString('<Ping xmlns="http://Thermo.Connect">' + sLineBreak);
WriteString('</Ping>' + sLineBreak);
WriteString('</s:Body>' + sLineBreak);
WriteString('</s:Envelope>' + sLineBreak);
except;
result.Free;
raise;
end;
end;
var
InetRoot: HINTERNET;
InetConnect: HINTERNET;
Request: HINTERNET;
begin
InetRoot := InternetOpen('GabeCode', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
try
InetConnect := InternetConnect( InetRoot, 'thermo-pc:2021', 0, '',
'', INTERNET_SERVICE_HTTP, 0, Cardinal(Self));
try
Request := HttpOpenRequest( InetConnect, 'POST', 'WSHCSConnect', 'HTTP/1.1', nil, nil,
INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_NO_CACHE_WRITE,
0);
try
// build add header items to the post request
with BuildHeader do
try
HttpAddRequestHeaders(Request, PChar(DataString), Length(DataString), HTTP_ADDREQ_FLAG_ADD);
finally
Free;
end;
// build the body of data being posted and send the post
with BuildBody do
try
if not HttpSendRequest(Request, nil, 0, PChar(DataString), Length(DataString)) then
HandleError(GetLastError);
finally
Free;
end;
finally
InternetCloseHandle(Request);
end;
finally
InternetCloseHandle(InetConnect);
end;
finally
InternetCloseHandle(InetRoot);
end;
end;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
6444 次 |
最近记录: |