我已经建立了世界上最愚蠢,最简单的SOAP服务器,在约3次点击,在Visual Studio中。在Visual Studio 2010中的具体步骤:首先创建一个新的项目作为一个Web应用程序,然后添加一个类型的Web服务的一个新项目。 (见图片公认的答案here。)肥皂服务器服务服务1有一个简单的方法的GetData:
从clientService1.pas一个片段,创建使用WSDL进口商...
IService1 = interface(IInvokable)
['{967498E8-4F67-AAA5-A38F-F74D8C7E346A}']
function GetData(const value: Integer): string; stdcall;
function GetDataUsingDataContract(const composite: CompositeType2): CompositeType2; stdcall;
end;
当我尝试运行此方法,如下所示:
procedure TForm3.Button1Click(Sender: TObject);
var
rio : THTTPRIO;
sv:IService1;
addr : string;
data : string;
begin
//addr := '....'; // url from visual studio 2010 live debug instance.
rio := THTTPRIO.Create(nil);
sv := GetIService1( true, addr, rio );
try
data := sv.GetData( 0);
Button1.Caption := data;
finally
sv := nil;
rio.Free;
end;
end;
我得到的错误是这样的:
ESOAPHTTPException:
The handle is in the wrong state for the requested operation -
URL:http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary1/Service1/ -
SOAPAction:http://tempuri.org/IService1/GetData'.
当我将URL粘贴入一个Web浏览器的URL正常工作,所以通常的回答是,在德尔福的SOAP代码有没有注意到一个HTTP失败的倾向,似乎并不容易。相反,它似乎我是(a)在经历WinInet的破损(已知某些版本的Windows发生),或(b)做错了什么?
在我看来,任何人谁拥有的Visual Studio和Delphi都安装,应该可以尝试让在Visual Studio交谈在Delphi中SOAP客户端虚拟启动SOAP服务器,而无需任何努力都没有。但我不能找出最简单的事情。
有一段时间,有一个关于在现在早就从Embarcadero的论坛中删除,由布诺巴伯,一个Embarcadero公司职员谈话误差讨论。
布鲁诺说:
你好,
我已SOAPHTTPTrans.pas的一个补丁版本,其中包含此修复此问题:
[论坛链接节录,它没有了,反正工作,后走了]
你仍然可以超越如在所提及的C ++生成器部分中描述的事件;或者,更简单,至少对德尔福的用户,只需将更新SOAPHTTPTrans.pas添加到您的应用程序的项目。让我们知道,如果不为你工作。
干杯,
布诺
你可以得到修复和它在原有论坛的音符从以下pastebin link和bitbucket,所以你不必提取周围的文本文件格式。
沃伦更新2016年我被人谁试图使用修复德尔福XE,这个修复程序不会对他们在德尔福工作XE通知。任何进一步更新代码到位桶是解决剩余的错误,将不胜感激。
我跑进手柄处于错误状态在2018年11月所请求的操作问题,采用Delphi东京10.2.3,然后看着下the pastebin link在Arjen's answer代码补丁。
该代码是很老的测试代码将不再有效(SOAP服务不可用)。此外,它是从布诺的代码是什么,他究竟打补丁目前还不清楚。
比较该源,并从我的Delphi版的一个似乎这些都是HandleWinInetError
过程中的(二)需要修改(“PATCH HERE”):
function THTTPReqResp.HandleWinInetError(LastError: DWord;
Request: HINTERNET;
RaiseError: Boolean): DWord;
function CallInternetErrorDlg: DWord;
var
P: Pointer;
begin
Result := InternetErrorDlg(GetDesktopWindow(), Request, LastError,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS or
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
{ After selecting client certificate send request again,
Note: InternetErrorDlg always returns ERROR_SUCCESS when called with
ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED }
if LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED then
Result := ERROR_INTERNET_FORCE_RETRY;
end;
const
{ Missing from our WinInet currently }
INTERNET_OPTION_CLIENT_CERT_CONTEXT = 84;
var
Flags, FlagsLen, DWCert, DWCertLen: DWord;
ClientCertInfo: IClientCertInfo;
CertSerialNum: string;
{$IFDEF CLIENT_CERTIFICATE_SUPPORT}
hStore: HCERTSTORE;
CertContext: PCERT_CONTEXT;
{$ENDIF}
begin
{ Dispatch to custom handler, if there's one }
if Assigned(FOnWinInetError) then
Result := FOnWinInetError(LastError, Request)
else
begin
Result := ERROR_INTERNET_FORCE_RETRY;
{ Handle INVALID_CA discreetly }
if (LastError = ERROR_INTERNET_INVALID_CA) and (soIgnoreInvalidCerts in InvokeOptions) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@Flags), FlagsLen);
end
else if (LastError = ERROR_INTERNET_SEC_CERT_REV_FAILED) and (soIgnoreInvalidCerts in InvokeOptions) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_REVOCATION;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(@Flags), FlagsLen);
end
{$IFDEF CLIENT_CERTIFICATE_SUPPORT}
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) and
Supports(Self, IClientCertInfo, ClientCertInfo) and
(ClientCertInfo.GetCertSerialNumber <> '') then
begin
CertSerialNum := ClientCertInfo.GetCertSerialNumber();
hStore := ClientCertInfo.GetCertStore();
if hStore = nil then
begin
hStore := CertOpenSystemStore(0, PChar('MY'));
ClientCertInfo.SetCertStore(hStore);
end;
CertContext := FindCertWithSerialNumber(hStore, CertSerialNum);
if CertContext <> nil then
begin
ClientCertInfo.SetCertContext(CertContext);
InternetSetOption(Request, INTERNET_OPTION_CLIENT_CERT_CONTEXT,
CertContext, SizeOf(CERT_CONTEXT));
end
else
begin
if RaiseError then RaiseCheck(LastError); // PATCH HERE
Result := CallInternetErrorDlg;
end;
end
{$ENDIF}
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) and (soPickFirstClientCertificate in InvokeOptions) then
begin
{ This instructs WinInet to pick the first (a random?) client cerficate }
DWCertLen := SizeOf(DWCert);
DWCert := 0;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT,
Pointer(@DWCert), DWCertLen);
end
else
begin
if RaiseError then RaiseCheck(LastError); // PATCH HERE
Result := CallInternetErrorDlg;
end;
end;
end;
需要注意的是RAISEERROR过程参数甚至没有这个补丁之前使用;-)
下面是使用SOAP服务从NOAA的National Digital Forecast Database (NDFD) SOAP Web Service一些测试代码:
Uses SOAP.SOAPHTTPTrans;
const Request2 =
'<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">' +
' <soapenv:Header/>' +
' <soapenv:Body>' +
' <ndf:NDFDgenByDay soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' +
' <latitude xsi:type="xsd:decimal">38.9936</latitude>' +
' <longitude xsi:type="xsd:decimal">-77.0224</longitude>' +
' <startDate xsi:type="xsd:date">%tomorrow%</startDate>' +
' <numDays xsi:type="xsd:integer">5</numDays>' +
' <Unit xsi:type="dwml:unitType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">e</Unit>' +
' <format xsi:type="dwml:formatType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">12 hourly</format>' +
' </ndf:NDFDgenByDay>' +
' </soapenv:Body>' +
'</soapenv:Envelope>';
const URL2= 'https://graphical.weather.gov:443/xml/SOAP_server/ndfdXMLserver.php';
procedure TFrmHandleWinINetError.Button1Click(Sender: TObject);
var
RR: THTTPReqResp;
Response: TMemoryStream;
U8: UTF8String;
begin
RR := THTTPReqResp.Create(nil);
try
try
RR.URL := URL2;
RR.UseUTF8InHeader := True;
RR.SoapAction := 'NDFDgenByDay';
Response := TMemoryStream.Create;
RR.Execute(Request2, Response);
SetLength(U8, Response.Size);
Response.Position := 0;
Response.Read(U8[1], Length(U8));
ShowMessage(String(U8));
except
on E:Exception do ShowMessage('ERROR CAUGHT: ' + e.message);
end;
finally
Response.Free;
RR.Free;
end;
end;
end;
如果没有在URL的尾部补丁错误被发现,但在域名错误,只是触发一个空的错误消息。 随着这些补丁也抓住了。
我有一个报道下数RSP-21862在RAD Studio的质量门户问题
使用您自己的风险,并请将任何额外的结果。
另外:这个问题在Delphi中被定格在2018年12月10.3力和质量门户问题与下面的评论关闭:
在RAD Studio在10.3 THTTPReqResp的实施改变,并与THTTPClient取代。所以,这个问题已不再适用。
我还没有证实这一点。