分享
 
 
 

C++ Builder 6 BizSnap/SOAP/WebService(2) -- 通过 SOAP 传递自定义类型数据(改)

王朝c/c++·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

说明:本文经过一些改动,纠正了一些问题,因为原文无法修改,只好重发。

不久前我收到几位朋友发来Mail说明他们在按照本文所述进行WebService应用开发时碰到的一个问题:在用ISAPI方式编写本文例子程序时发生AV错误。根据改进后的本例子程序修改了本文,请注意文中加粗部分内容。

--2002-8-17

本文将做一个略复杂的例子,实现通过 SOAP 传递自定义的数据类型。本例子的功能是在服务端通过 ADO 的数据访问控件取得数据表内容,然后将其通过 SOAP 传递到客户端再显示。

服务端:

1.New|WebServices|Soap Server Application ,如下图,与 Delphi 6 + Update 2 相比,除了左上角的图标以外,完全相同:

选 Web App Debugger executeable 类型, CoClass Name 为:wadSoapDemo2 ,如下图:

确定后将自动提示是否要新建一个接口,如下图,确定即可打开新建接口向导,如果要以后再增加接口,可以在 New|WebServices 中选择 SOAP Server Interface 同样可打开新建接口向导:

2.新建接口向导如下图,输入接口名:DataTable 即可生成一个 SOAP 服务端接口:

关于此向导的其它说明见《C++ Builder 6 BizSnap/SOAP/WebService(1) -- 一个 Hello world! 的例子》(以下简称《(1)》);

3.(注意:原文的这部分有错,现在为修改后的)新建一个 DataModule ,放入四个数据库控件: ADOConnection1, ADODataSet1, DataSetProvider1, ClientDataSet1 ,其各属性设置如下表:

ADOConnection1

ConnectionString = "Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=Northwind;Data Source=raptor\neutrino";

LoginPrompt = false;

ADODataSet1

Connection = ADOConnection1;

CommandText = "select FirstName, LastName from Employees";

DataSetProvider1

DataSet = ADODataSet1;

ClientDataSet1

ProviderName = DataSetProvider1;

完成后的 DataModule 如下图:

(关于这部分的补充说明):原用 dbExpress 在用于 ISAPI 时会出现“Unable load dbexpint.dll”的错误,所以改用 ADO 。另,因没有 ADOClientDataSet 控件,否则若是 BDE/dbExpress/IBExpress 则只需要两个控件即可。要把数据控件放在单独的 DataModule ,而不能放在 WebModule 中的原因见《Web 应用的执行过程 -- 谈谈 WAD/CGI/ISAPI 的区别》,本文例子仅供参考,建议在涉及数据库操作的应用中,最好用 SOAP Server Data Module (如《C++ Builder 6 BizSnap(3) -- DataSnap 数据库应用》)。

4.SaveAll , Unit1 命名为: MainWM , Unit2 命名为 Demo2DM , Project1 命名为: Demo2 , DataTable 不改名;

5.在接口单元的头文件(DataTable.h)中增加一个自定义的类 -- TDataSetPack ,如下:

class TDataSetPack : public TRemotable {

private :

int FCount;

AnsiString FXMLData;

public :

__fastcall TDataSetPack( TCustomClientDataSet * aClientDataSet )

: TRemotable(),

FCount( aClientDataSet->RecordCount ),

FXMLData( aClientDataSet->XMLData )

{

}

__published:

__property int Count = { read = FCount };

__property AnsiString XMLData = { read = FXMLData };

};

自定义 SOAP 数据类型必须是从 TRemotable 类派生的,这一点与 Delphi 相同。其中 ClientDataSet 的 XMLData 属性是从 Delphi 6 开始新增的。其实 XMLData 中已经包含了记录数信息, Count 属性并不是必须的,这里为了演示自定义 SOAP 数据类型的使用,所以加入这个属性。注意:要在此头文件中加入:#include <DBClient.hpp>

5.定义及实现 GetEmployeeTable 函数,其方法与《(1)》中相同,下面是在接口头文件(DataTable.h)和单元文件(DataTable.cpp)中的接口/类定义和我们加入的方法及其实现:

// DataTable.h

__interface INTERFACE_UUID("{CF057C28-4130-4508-9F24-0BBD1C2CA5F0}")

IDataTable : public IInvokable

{

public:

virtual TDataSetPack * GetEmployeeTable( void ) = 0; // 新增方法

};

typedef DelphiInterface _di_IDataTable;

// DataTable.cpp

class TDataTableImpl : public TInvokableClass, public IDataTable

{

public:

TDataSetPack * GetEmployeeTable( void ); // 新增方法

/* IUnknown */

HRESULT STDMETHODCALLTYPE QueryInterface(const GUID& IID, void **Obj)

{ return GetInterface(IID, Obj) ? S_OK : E_NOINTERFACE; }

ULONG STDMETHODCALLTYPE AddRef() { return TInterfacedObject::_AddRef(); }

ULONG STDMETHODCALLTYPE Release(){ return TInterfacedObject::_Release(); }

/* Ensures that the class is not abstract */

void checkValid() { delete new TDataTableImpl(); }

};

// 新增方法的实现:

// 如果是 CGI/ISAPI 应用,则需要新建 DataModule1 ,相应修改见后面说明

// 打开 ClientDataSet ,构造 TDataSetPack ,

// 关闭 ClientDataSet 和数据库连接

// 返回结果

TDataSetPack * TDataTableImpl::GetEmployeeTable( void )

{

// 如果是 CGI/ISAPI 则要此句

// Application->CreateForm(__classid(TDataModule1), &DataModule1);

DataModule1->ClientDataSet1->Open();

TDataSetPack * p = new TDataSetPack( DataModule1->ClientDataSet1 );

DataModule1->ClientDataSet1->Close();

DataModule1->ADOConnection1->Close( );

return p;

}

除了方法的实现部分以外,其它部分与《(1)》基本上一样。这个方法的实现功能,正如程序中的注释说明的那样,用于取得数据集并转换为我们定义的数据类型后返回。

(关于这部分的补充说明):注意如果是 CGI/ISAPI 应用,其中的 DataModule1 是动态创建(原因如《Web 应用的执行过程 -- 谈谈 WAD/CGI/ISAPI 的区别》一文所述),所以相应的要把 Project|Source ( 即 Demo2CGI.cpp/Demo2ISAPI.cpp )中如下代码片段那样将自动创建语句去掉。

Application->CreateForm(__classid(TWebModule1), &WebModule1);

// 如果是 CGI/ISAPI 应用则不要此句

// Application->CreateForm(__classid(TDataModule1), &DataModule1);

Application->Run();

6.注册接口及其实现类的部分也与《(1)》相同,就不再赘述了。

7.编译之即可产生: Demo2.exe ;

先运行一次 Demo2.exe ,完成注册的工作后启动 Web App Debugger 。打开浏览器, 输入 URL 为: http://localhost:1024/Demo2.wadSoapDemo2 即可看到一个标准的 SOAP 应用说明页面,点击进入相应链接即可看到相关的 WSDL ,在其中可以看到我们自定义的数据类型说明,如下面的 WSDL 片断所示:

<types>

<xs:schema targetNamespace="urn:DataTable" xmlns="urn:DataTable">

<xs:complexType name="TDataSetPack">

<xs:sequence>

<xs:element name="Count" type="xs:int"/>

<xs:element name="XMLData" type="xs:string"/>

</xs:sequence>

</xs:complexType>

</xs:schema>

</types>

客户端程序:

1.New|Application 新建一个一般 VCL 应用程序;

2.SaveAll , Unit1 命名为 ClnMain , Project1 命名为 Client ;

3.New|Web Services|Web Services Importer :

在下图中的URL中输入: http://localhost:1024/Demo2.wadSoapDemo2/wsdl/IDataTable,

如果上面用浏览器可以看到正确的 XML 文档的话,选择“Next”后将产生导入的结果,如下图:

其中有我们在服务端定义的数据类型 TDataSetPack 、接口 IDataTable 及其方法 GetEmployeeTable ,选择完成即可生成接口单元;

4.SaveAll, IDataTable 单元不改名保存,再在 ClnMain 中 #include IDataTable.h ;

5.在 Form 上放上一个 ClientDataSet, DataSource, DBGrid, Button, Label 等几个控件,其各属性设置如下表:

ClientDataSet1

全部默认

DataSource1

DataSet = ClientDataSet1;

DBGrid1

DataSource = DataSource1;

Button1

Caption = "Fetch data";

Label1

Caption = "Count:0";

完成后的 Form 如下图:

6.双击 Button1 输入下面的程序:

void __fastcall TForm2::Button1Click(TObject *Sender)

{

TDataSetPack * p = GetIDataTable()->GetEmployeeTable();

Label1->Caption = AnsiString( "Count:" ) + IntToStr( p->Count );

ClientDataSet1->XMLData = p->XMLData;

}

7.编译运行,按 Button1 , DBGrid1 中将显示服务端返回的数据集内容, Label1 中将显示记录数,如下图(说明,此图仍为原来用 InterBase 时的数据);

这只是一个简单的数据库访问的例子,只能从服务端取回数据集, C++ Builder 6 中已经将 MIDAS/DataSnap 和 SOAP/WebService 结合,可以通过 SOAP/WebService 实现非常强大的数据库操作能力,这将在以后的文章中介绍。

[Mental Studio]猛禽 Apr.30-02

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有