Delphi6 的SP2升級問題,怎麼辦呢?有沒有webservice,Soap高手? (100分)

  • 主题发起人 主题发起人 wen
  • 开始时间 开始时间
W

wen

Unregistered / Unconfirmed
GUEST, unregistred user!
沒升級之前寫的webservice運行得好好的,(sp1,sp2)升級之後客戶端再也連不上了.
我出現的問題是:
1 sp1及sp2升級後,客戶端調用未升級的前的webservice產生如下錯誤:
Unable to retrieve the URL endpoint for service/port...
但在未升級之前是程式是正常運行的.
2 sp1及sp2升級後,試做一webservice,IE中正常顯示WSDL
但用導向生客戶端接口後,客戶端調用時出錯為:
Unsupported calling convention:REGISTER
3 並且參數類型也變了,例原widestring-->升級後string.
誰能告訴我為什麼??
 
沒人知道?
升級後問題不少,
新版本下做的webservice,客戶端連不上,但在ie中輸入地址能產生xml文件.
 
你是做web service的三层数据库吗?
D6加了UPDATE2以后确实在这方面有个BUG!我当初也遇到了,后来请教了猛禽!他为这个问题
又写了一篇文章。去看看吧!
http://www.csdn.net/develop/article/13/13488.shtm
 
猛禽(Raptor)兄的DELPHI 6 Update 2# 的 Bug 及其解决方法
Borland发布了对 Delphi 6 意义重大的第二个补丁,在SOAP/Web Service开发方面
有了很大的增强,详见《DELPHI 6.02 抢先研究 -- BizSnap/SOAP/WebService 之
-- 补丁2#的意义》。不过有一个方面我在那篇文章里没有说到,那就是用 SOAP 进
行多层应用开发,当时我对这部分只是大致看了一下,没发现与补丁前相比有什么太
多的不同,所以也没在意,直到不久前,一位叫 liaoqian 的网友给我发来 Mail 询
问有关这方面的问题时,我才注意到 Delphi 6 Update 2# 在这部分有相当大的变化
(当然不是表面上的),并且存在一个小 Bug 。 首先仿照《DELPHI 6 抢先研
-- BizSnap/SOAP/WebService 之三 -- 用 SOAP 实现三层数据库应用》 中的例子
做一个 WebService 三层数据应用。当出现上图所示的自动询问是否产生一个服务端
接口的对话框时选择“No”,然后新建 SOAP Server Data Module ,其它操作与
《之三》相同。完成之后在IE中输入:
http://localhost:1024/Demo3.wadSoapDemo3/wsdl 将可以看到如下的接口列表,相
比《之三》一文,可以看出增加了一个 IAppServerSOAP 接口,并且其
IWSDLPublish 接口的 Namespace URI 也有不同。
Port Type Namespace URI Documentation WSDL
IAppServer urn:Midas-IAppServer IAppServer
IAppServerSOAP http://www.borland.com/namespaces/Types
IAppServerSOAP
ISoapDemo3DM urn:SvrDMSoap-ISoapDemo3DM ISoapDemo3DM
IWSDLPublish http://www.borland.com/namespaces/Types Lists all the
PortTypes published by this Service IWSDLPublish
如果注意的话还可以发现一点问题,即:输入
http://localhost:1024/Demo3.wadSoapDemo3 不会看到 Delphi 6.02 写的一般
WebService 那样的一个页面,这有点不正常。
到编写客户端程序的时候,问题就出现了:在 ClientDataSet 的 ProviderName 属
性中下拉,将不会看到任何可用的 ProviderName ,但一闪而逝的服务端窗体表明服
务端是运行了的。通过察看 Web App Debugger 的记录信息可以看到如下的 SOAP 错
误响应:
<?xml version="1.0" encoding='UTF-8'?>
<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" > <soap-env:body>
<soap-env:fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>
No invokable class registered that implements interface SOAPMidas.IAppServerSOAP of (soap action/path) "http://www.borland.com/namespaces/Types-IAppServerSOAP"
</faultstring>
</soap-env:fault>
</soap-env:body>
</soap-env:envelope>
注意其中 faultstring 标记中的信息,它说明了错误的原因是“没有可调用的
已注册的 IAppServerSOAP 接口实现类”。如果不理睬这个问题,直接把
DataSetProvider1 写到 ClientDataSet1 的 ProviderName 属性中,再将
ClientDataSet1 的 Active 属性设置为 true 将直接出现一个异常,其内容便是上
面的 faultstring 的内容。
我非常喜欢包括 Delphi 在内的 Borland 的几乎所有产品,也非常信任
Borland ,这种感情来源于我七八年来使用过的数十个不同的 Borland 的产品及其
不同版本,所以我不喜欢一些人在一碰到问题时就没理由地埋怨开发工具有 Bug 。
虽然有很多传闻说 Borland 的产品 Bug 如何的多,其实有软件就有 Bug ,我也不
是说 Borland 就一定没有 Bug , Borland 当然也有 Bug ,在本站就曾几次提到,
难道 Microsoft 就没有 Bug 吗?
但这一次,我几乎可以肯定是 Delphi 6 Update 2 所带来的 Bug ,因为在打补
丁2#之前,我也是完全按照上面的做法一步步做的,没有任何问题,打了补丁2#就出
现了这样的问题。即便如此,我还是要找到具体的证据来证明这是一个 Bug 并要找
到解决的办法,所以我读了 Delphi 6.02 的部分 SOAP 相关源代码,并进行了调
试。
附:《设置源码察看和调试》
SOAP 部分源码察看设置:在 Delphi 6 中选择 Tools|Environment Options 选
中 Library 页,在 Browsing path 中加入路径:$(DELPHI)/source/Soap ,然后就
可以在程序中通过 Ctrl+MouseLeftButton 快速跳到相应的 SOAP 源码文件中了。
源码调试设置:在 Delph 6 中选择 Project|Options 选中 Compiler 页,将其
中 Debugging 框中的 Use Debug DCUs 一项选取后,重新编译程序,即可调试进入
VCL 的源码中了。
通过跟踪调试发现异常发生在 SOAPHTTPPasInv 单元中的 Procedure THTTPSoapPascalInvoker.DispatchSOAP 中:
...
if IntfInfo = nil then
raise Exception.CreateFmt(SInvInterfaceNotReg, [SoapAction])
else
if InvClassType = nil then
RaiseNoIntfException(SoapAction)
...
因为其中 InvClassType 为 Nil ,所以导致了那个异常。这提供的信息和前面
的出错信息其实是一样的:即 IAppServerSOAP 接口的实现类不存在或未注册。所以
我又找到了 IAppServerSOAP 接口的定义,在 SOAPMidas 单元中:
IAppServerSOAP = interface(IInvokable)
['{C99F4735-D6D2-495C-8CA2-E53E5A439E61}']
function SAS_ApplyUpdates(...): OleVariant;
stdcall;
function SAS_GetRecords(...): OleVariant;
stdcall;
function SAS_DataRequest(...): OleVariant;
stdcall;
function SAS_GetProviderNames: TWideStringDynArray;
stdcall;
function SAS_GetParams(...): OleVariant;
stdcall;
function SAS_RowRequest(...): OleVariant;
stdcall;
procedure SAS_Execute(...);
stdcall;
end;
熟悉 MIDAS 技术的人看了这段代码,立即可以发现它与 IAppServer 接口极其
相似,只是在 IAppServer 中,那些方法都是以 AS_ 开头,而这里是以 SAS_ 开
头。那么为什么既然已经有了一个 IAppServer 接口了, Borland 还要在 Update 2
加入这么一个 IAppServerSOAP 接口呢?在打补丁2之前,我也看过 SOAP 的部分代
码,那时的 SOAP Server Data Module 是从 IAppServer 派生的,虽然 IAppServer
并不是从 IInvokable 派生的(按 Delphi 6 的要求,所有 SOAP 接口都要从
IInvokable 接口派生),但其实 IInvokable 是直接从 IInterface 派生的,与
IInterface 完全相同,而 IInterface 其实就是所有 COM 接口的祖先接
口--IUnknown,而 IAppServer 是从 IDispatch 接口(是 COM 的一个主要接口,用
于 Automation ,其祖先当然也是 IUnknown)派生出来的,所以直接用 IAppServer
也并无不可。
在 IAppServerSOAP 接口定义前面有一段注释,大意就是说: IAppServerSOAP
用 StdCall 类型的方法调用替代了 IAppServer 中的 SafeCall 类型的方法调用,
为的是在不支持 SafeCall 的环境中也可以实现 IAppServer 的功能。这就是
IAppServerSOAP 出现的原因。
了解了这些就好多了。所有的 SOAP Server Data Module 都是从
TSoapDataModule 派生的,它定义在 SOAPDm 单元中,其中有如下代码:
{ IAppServerSOAP }
function SAS_ApplyUpdates(...): OleVariant;
virtual;
stdcall;
function SAS_GetRecords(...): OleVariant;
virtual;
stdcall;
function SAS_DataRequest(...): OleVariant;
virtual;
stdcall;
function SAS_GetProviderNames: TWideStringDynArray;
virtual;
stdcall;
function SAS_GetParams(...): OleVariant;
virtual;
stdcall;
function SAS_RowRequest(...): OleVariant;
virtual;
stdcall;
procedure SAS_Execute(...);
virtual;
stdcall;
这里就是 IAppServerSOAP 接口的实现,由于所有的 SOAP Server Data Module
都是从 TSoapDataModule 派生的,所以 IAppServerSOAP 接口的实现类一定是已经
实现的,但有没有注册呢?在我们的 SOAP Server Data Module 单元--SvrDMSoap
中有如下代码:
procedure TSoapDemo3DMCreateInstance(out obj: TObject);
begin
obj := TSoapDemo3DM.Create(nil);
end;

initialization
InvRegistry.RegisterInvokableClass(TSoapDemo3DM,
TSoapDemo3DMCreateInstance);
显然它也已经注册了,但为什么会出错呢?看看 ISoapDemo3DM 接口的 WSDL
吧……怎么只有 AS_XXX ?没有 SAS_XXX ?原来如此,服务端只导出了
IAppServer 接口,并没有导出 IAppServerSOAP 接口。这就是问题所在!
再来看看 SvrDMSoap 单元:
ISoapDemo3DM = interface(IAppServer)
['{4F618288-9F81-4090-81EF-4ACE0BF6D0BE}']
end;
TSoapDemo3DM = class(TSoapDataModule, ISoapDemo3DM, IAppServer)
原来如此,原来 ISoapDemo3DM 居然还是从 IAppServer 接口派生的,显然这是
SOAP Server Data Module Wizard 的一个 Bug ,它还是按 IAppServer 接口的方法
来生成 SOAP Server Data Module 的。知道问题的所在就好办了,将上面的代码中
的两个 IAppServer 都改为 IAppServerSOAP ,然后重新编译。再来看看客户端程
序,一切正常了, ISoapDemo3DM 的 WSDL 也正确地导出了 SAS_XXX ,特别是
hhttp://localhost:1024/Demo3.wadSoapDemo3 也可以看到标准的 Delphi 6.02 的
WebService 页面了。
至此,这个 Bug 已经完全解决。另外,要补充说明的是:在 C++ Builder 6 中
不存在这个问题。
 
多謝兩位!
我出現的問題是:
1 sp1及sp2升級後,客戶端調用未升級的前的webservice產生如下錯誤:
Unable to retrieve the URL endpoint for service/port...
但在未升級之前是程式是正常運行的.
2 sp1及sp2升級後,試做一webservice,IE中正常顯示WSDL
但用導向生客戶端接口後,客戶端調用時出錯為:
Unsupported calling convention:REGISTER
那位能幫我?
 
能否把功能性的代码迁移到D6加U2的环境下再编译一次!
 
好象MIDAS也有问题的?
在客户计算机,无法访问服务器,我用D6U2编译原来的D6源程序在服务端运行正常;
但是客房户机不行,换回没事的,记不起来等稳定再说的
 
好像客戶端與服務端都要重新編譯才可以.
update sp2之後,運行速度加了不少.
那位能告訴我:升級sp2後.
Service Activation model中的:
Per Request 及Global的含義是什麼,有沒有起作用,我查看了二者的代碼,好像沒有什麼不同.
 
多人接受答案了。
 
后退
顶部