从Interface到COM+(SOAP WebService)
前言:
当你把一个函数定义在方法内部,那这个函数只能供这个方法使用。你把一个函数定义在单元的实现部份,那么这个函数只能供在此代码之后的所有方法使用。
当你把一个函数定义在单元接口内,那么整个单元内的方法都可以使用,引用这个单元的其它单元内方法也可以使用。
当C++或其它开发工具想使用你这个函数时,你有二种选择,把这个函数封装成DLL或封装成COM,输出这个函数功能。
以上的这些情况,都只能在本机使用,最多只能在局域网内使用,如果你想定义一个方法,全球都能用,那怎么办?除了使用WebService你没有其它选择。
一、从InterfaceàCOMàCOM+àDCOMàSOAP WebService这些技术是层层推进,一环扣一环的,前者是后者的依赖基础,后者是从前者发展衍生出来的。
二、什么是SOAP WebService?他们是解决什么问题的?怎么用?
1、什么是SOAP,它与WebService是个什么关系?
①SOAP是肥皂,当然这是不是肥皂的意思,SOAP=Sample ObjectAccess Protocol(简单对象访问协议),它是一个Write Protocol(写协议)
②因为它是个写协议,所以他必须以HTTP(超文本传输协议)做为载体,进行通信。
③ SOAP是个带写协议的数据封包,这个封包里面的内容格式是标准的XML,里面定义了要获取哪个功能服务。
④、WebService接受并解析SOAP封包,然后去查找SAOP封包所需服务的具体实现,WebService所提供的服务都是以接口形式编写的,所认要获取它的服务,必须通过接口进行调用。
⑤、SOAP与WebService是不可分开的讲的,他们是一体的。
⑥、当WebService找到相应的服务调用成功后,把结果同样封装成一个SOAP数据包返回给客户端。
⑦、WebService能提供什么服务,客户端不知道,这时客户端只要连接到一个WebService,WebService就会使用一个叫WSDL的标准输出接口(WSDL=Web Service Description Language Web服务描述语言)把WebService的所有服务功能封装成XML格式的SOAP包返回给客户端。
如何建立一个WebService?
FileàNewàOtheràWebServiceàSOAP Service Application这时向导会放你要创建哪种类型的WebService,选择哪一种都可以,他们之间可以互相转换,为了方便调试一般建立Web App Debugger类型的WebService。这时向导会问询是否创建WebService模块和相对应的接口单元与实现单元,一般选择是。这时在WebService Module中会自动加入三个组件,HTTPSOAPDispathcher,它是SOAP调度器,会拦截HTTP中SOAP封包的请求,解析SOAP封包,把SOAP中的请求分泒给HTTPSoapPascalInvoker,HTTPSoapPascalInvoker根据得到的请求,激活WebService中的相应服务。获得服务后的内容,由WSDLHTMLPublish负责把结果封包成HTML返回给客户端。WSDHTML有一个属性AdminEnabled把它设为True就可以在IE查看WebService提供的服务清单.(如果手工调Web App Debugger)Delphi2007及以后的版本需要手动启动Bin下的ServerInfo.exe,调试用Tools->Web App Debugger,注意必须先启动ServerInfo.exe。
如下是WebService的服务器代码,这段代码很简单就是输出一行信息.
接口单元代码
{ Invokable interface ImyShowMessage }
unit myShowMessageIntf;
interface
uses InvokeRegistry, Types, XSBuiltIns;
type
{ Invokable interfaces must derive from IInvokable }
ImyShowMessage = interface(IInvokable)
['{3B31C8F5-725D-470A-89CF-02D881356905}']
function theShowMessage():string;stdcall;//为了让其它语言开发工具调用,必须使用StdCall;方法最好使用函数,而不使用过程
{ Methods of Invokable interface must not use the default }
{ calling convention; stdcall is recommended }
end;
implementation
initialization
{ Invokable interfaces must be registered }
InvRegistry.RegisterInterface(TypeInfo(ImyShowMessage));
end.
实现单元代码
{ Invokable implementation File for TmyShowMessage which implements ImyShowMessage }
unit myShowMessageImpl;
interface
uses InvokeRegistry, Types, XSBuiltIns, myShowMessageIntf;
type
{ TmyShowMessage }
TmyShowMessage = class(TInvokableClass, ImyShowMessage)
Public
function theShowMessage():string;stdcall;//为了让其它语言开发工具可以调用,最好使用Stdcall对方法进行后指示。
end;
implementation
{ TmyShowMessage }
function TmyShowMessage.theShowMessage: string;
begin
Result := 'I Love Delphi';
end;
initialization
{ Invokable classes must be registered }
InvRegistry.RegisterInvokableClass(TmyShowMessage);
end.
Form单元代码
unit Unit1;
interface
uses
SysUtils, Classes, Forms;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses SockApp;
{$R *.dfm}
initialization
TWebAppSockObjectFactory.Create('Demo')
//对像工厂创建的实例,这个名字在调用时必须使用到
end.
下面讲解,如何调用这个WebService
1,调用很简单,建一个普通工程,在Form上加入WebServiceàHTTPRIO组件。HTTPRIO这个组件,它可以直接连接到WebService并读取相应的服务
在这里说说HTTPRIO组件的URL属性与WSDLLocation属性。
1, 如果WebService是Delphi开发的,那么使用HTTPRIO的URL或WSDLLocation属性与WebService连接,只要连接成功,可以在Service属性中选择相应的接口服务,在Port属性中可以选择相应的接口的端口。
2, 如果WebService不是Delphi开发的,那只能用WSDLLocation属性与WebService连接,连接成功在Service属性中选择相应的接口服务,在Port属性中选择相对的接口端口。
3, 在URL里面用的是SOAP路径,在WSDLLocation中用的是WSDL路径,如何查看WSDL可以用IE打开一个WebService。
4, 如,URL是这样写的http://localhost:8081/Project1.demo/soap注意EXE文件的后缀名为建立WebService时的coClass名称+SOAP就行了。WSDLLocation是这样写的http://localhost:8081/Project1.Demo/wsdl/ImyShowMessage。EXE文件的后缀名为建立WebService时的coClass名称+wsdl+指定接口服务名称。如果是CGI或ISAPI就直接是WebService文件名,而没有coClass名称。
调用时:如果WebService是Delphi开发的,把创建WebService时产生的接口文件加到客户端工程中,在Form单元中引用就行,如果是其它语言开发的,那就用FileàNewàOtheràWebServiceàWSDL Import向导导入 如图
如下是调用WebService的客户端代码
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, InvokeRegistry, Rio, SOAPHTTPClient, StdCtrls;
type
TForm3 = class(TForm)
HTTPRIO1: THTTPRIO;
Button1: TButton;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
uses myShowMessageIntf;//这里引用的是WebService的接口单元
{$R *.dfm}
procedure TForm3.Button1Click(Sender: TObject);
begin
Edit1.Text := (HTTPRIO1 as ImyShowMessage).theShowMessage;
end;
initialization
end.
虽然这个例子没有什么实际应用,但是把WebService的原理是讲的比较清楚的
注意:IIS7启用CGI和ISAPI的方法如下:
Default Web Siteà处理程序映射à击CGI EXEà右边编辑权限à执行打勾。如果没有看到这个功能那么增加方法如下:控制面板à程序à打开或关闭Windows功能à把IIS相关的东西选上。这样处理后,把CGI或ISAPI类型的WebServer文件放到wwwRoot目录下,用IE可以看到SOAP或WSDL内容,如:http://localhost/Project1.exe/wsdl/ImyShowMessage,在这里就不需要端口号了.
------------------------------------------------------------------
上面讲解是的如何把方法做到WebService里,下面讲解WebService与数据库的结合,这是WebService应用的重点
一、 如何建立一个数据库应用的WebService?
1,FileàNewàOtheràWebService->SOAP Server Application,选择WebService服务器类型,如果是纯数据库服务器,不带方法输出,在创建向导问询是否Create Interface for SOAP module时,选择,no就行,如果又要带方法服务,那就选择yes。这样的创建与创建方法服务的WebService是一样的,只是没带接口单元文件与接口的实现单元文件。同样Web Module模块中自动加入三个组件HTTPSOAPDispatch,HttpSoapPascalInvoker,WSDLHtmlPublish,把WSDLHTMLPublish的Admin Enable 属性设为True
2,创建WebService数据库服务模块,FileàNewàOtheràWebServiceàSOAP Server Data Moduleà这是创建向导会要求输入数据库模块名称(Module Name)。注意,这个模块名称就是对外提供数据库服务的接口名称,客户端连接WebService时,必须要使用到这个名称。按我的习惯,一般把这个模块命名为DM。
3,到了这里,就象开发一般的应用数据库软件一样,把所有连接都放在这个DM文件里,注意,这里不放DataSource组件,每个数据库访问管道都配上一个DataSetProvider,客户端用的ClientDataSet只能挂接到这个DataSetProvider上访问后台数据库(访问的意思包括数据读取与数据写入)。一般DataSetProvider组件的AllowMultiRecordUpdates(允许多行记录同时更新,这个属性不是必须为true的)属性设为True。AllowCommandText(允许在DataSetProvider上下达SQL语句,这个属性是必须设为true的,否则ClientDataSet上的SQL语句传过来后无法执行)属性设为True。
5, 下面讲解如何连接数据库的WebService
6, 建立一个一般的Form,加入SOAPConnection组件。设置URL(URL里设的是SOAP,不是WSDL)。URL的写法是HTTP://WebSerice地址/WebService应用程式名称/SOAP/SOAP数据模块接口。如果是WAD的话,WebService应用程式名改为WebService应用程式名称.coClass名称,调试WAD时一定要让Web App Debugger这个服务程式运行,否则ClientDataSet解析不到ProviderName里面的名称。URLf地址如:http://localhost:8081/P_WebServiceData.DataBaseTest/SOAP/IDM。再加入一个ClientDataSet用RemoteServer属性挂接SOAPConnection组件。只要URL地址没有错误,在ProviderName属性里就可以把WebService中的数据模块中的DataProvider组件名称全部解析过来,然后选择要连接哪个DataProvider,这样连接任务就完成了,剩下的就是数据库开发部份了。