注:该文章节选自作者的《Visual FoxPro程序设计参考手册》
创建一个Web服务是一个复杂的过程,这涉及到要使用Internet信息服务(IIS)、Visual FoxPro COM服务程序和简单对象访问协议(SOAP)。在这节中将结合上节中介绍的XMLAdapter和在20.4节中介绍的CursorAdapter来建立一个可以通过HTTP进行获取和修改SQL Server 2000附带示例数据库Northwind中Customers表的Web服务实例。该Web服务的流程图18-11所示。可以看出,这是一个3层架构的客户/服务器模式。
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 332.25pt; HEIGHT: 38.25pt" type="#_x0000_t75"><imagedata o:title="18-11" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.png"></imagedata></shape>
图18-11 Web服务流程图
创建Web服务,首先要建立一个COM服务程序,然后才可以使用Visual FoxPro的Web服务发布向导将COM升迁为Web服务。
新建一个名为MyWebService的项目,然后在项目中使用以下代码创建一个叫做MyClass的.prg文件,在其中建立了一个ChangeCustomer类。
DEFINE CLASS <place w:st="on"><city w:st="on">ChangeCustomer</city><state w:st="on">AS</state></place> Session OLEPUBLIC
DataSession=2 &&私有数据工作期
PROCEDURE Init
SET MULTILOCKS ON
ENDPROC
PROCEDURE GetCustomerInfo HelpString "获取客户信息"
LOCAL oXMLAdapter AS XMLAdapter,oCA AS String,cXML AS String
oCA=CREATEOBJECT("MyCursorAdapter") &&建立CursorAdapter对象
oCA.CursorFill() &&按oCA的Alias属性指定的名称生成临时表
oXMLAdapter=NEWOBJECT("XMLAdapter") &&建立XMLAdapter
oXMLAdapter.AddTableSchema(oCA.Alias) &&加载临时表到XMLAdapter对象
oXMLAdapter.ToXML("cXML") &&生成XML字符串
RELEASE oXMLAdapter,oCA &&释放对象实例
RETURN cXML &&返回XML字符串
ENDPROC
PROCEDURE UpdateCustomer(cXML AS String) HelpString "更新客户信息"
LOCAL oXMLAdapter AS XMLAdapter,oCA AS CursorAdapter
oXMLAdapter=NEWOBJECT("XMLAdapter") &&建立XMLAdapter
oXMLAdapter.UTF8Encoded=.F.
oXMLAdapter.IsDiffGram=.T.
oXMLAdapter.LoadXML(cXML,.F.) &&加载XML
oCA=CREATEOBJECT("MyCursorAdapter")
oXMLAdapter.Tables(1).ChangesToCursor(oCA.Alias) &&还原缓冲表
oCA.CursorAttach(oCA.Alias) &&将还原出的缓冲表与CursorAdapter建立关联
=TABLEUPDATE(.T.) &&发送更新
RELEASE oXMLAdapter,oCA
ENDPROC
PROCEDURE Error(nError AS Integer,cMethod AS String,nLine AS Integer)
LOCAL cText AS String
cText=cMethod+" 错误号="+LTRIM(STR(nError,5))+" 行号="+LTRIM(STR(nLine,8))+" "+MESSAGE()
COMRETURNERROR(cText,_VFP.ServerName)
ENDPROC
ENDDEFINE
*!* 建立基于CursorAdapter的子类,用于连接到SQL Server
DEFINE CLASS <place w:st="on"><city w:st="on">MyCursorAdapter</city><state w:st="on">AS</state></place> CursorAdapter
Alias="Customer"
BreakOnError= .F.
DataSourceType="ODBC"
Tables="Customers"
SendUpdates=.T.
AllowDelete=.T.
AllowInsert=.T.
AllowUpdate=.T.
UpdateType=1 &&发送更新方式为UPDATE
WhereType=1 &&Where子句类型为仅由KeyFieldList属性指定的主关键字段组成
KeyFieldList="CustomerID"
UpdatableFieldList="CustomerID, CompanyName"
UpdateNameList="CustomerID Customers.CustomerID, CompanyName Customers.CompanyName"
BufferModeOverride= 5 &&开放式表缓存
cConnectionString="Driver={SQL Server};Server=localhost;Uid=sa;Pwd=;Database=northwind"
PROCEDURE Init &&类实例化时直接建立连接
This.DataSource=SQLSTRINGCONNECT(This.cConnectionString, .T.)
This.SelectCmd="SELECT CustomerID, CompanyName FROM Customers"
This.CursorSchema ="CustomerID C(5), CompanyName C(40)"
ENDPROC
FUNCTION Destroy() &&在释放对象时断开与SQL Server的连接
SQLDISCONNECT(This.DataSource)
ENDFUNC
ENDDEFINE
上面代码中的GetCustomerInfo( )方法用于将Customers的CustomerID和CompanyName字段中的所有内容以XML格式返回给客户端;UpdateCustomer( )方法根据客户端发送来的Diffgrams格式的XML更新到Customers表。
在17.4.2节中详细介绍了编译COM对象的方法与原理,因此这里只简单介绍步骤。在正式编译前,需要预编译一下自动服务程序,才可以设置自动服务程序的项目信息。单击项目管理器的Build(编译)命令按钮,打开Build Options(编译选项)对话框,选择Multi-threaded COM server(多线程COM服务程序)选项进行连遍,编译成功后,该COM组件自动在本地计算机的Windows中注册并可用。
在项目管理器上单击鼠标右键,在弹出的快捷菜单上选择Project Info(项目信息)菜单项,打开如图18-12所示Project Information对话框,在Servers选项卡的Instancing(实例)下拉列表中选择服务类型为Multi Use(多重使用)。
单击项目管理器中的Build按钮重新连编项目为Multi-threaded COM server。
要在服务器上发布Web服务,需要IIS的支持。IIS在Windows XP中是作为可选组件提供的,可以在Windows的控制面板中双击“添加或删除程序”图标打开“Windows组件向导”对话框,在组件列表中复选“Internet信息服务(IIS)”组件,并单击“下一步”按钮进行安装,如图18-13所示。安装成功后,可以打开Internet Explorer浏览器,在地址栏中输入“http://127.0.0.1”,可打开默认的站点页面。
<shape id="_x0000_i1026" style="WIDTH: 187.5pt; HEIGHT: 151.5pt" type="#_x0000_t75"><imagedata o:title="18-10" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image003.jpg"></imagedata></shape> <shape id="_x0000_i1027" style="WIDTH: 200.25pt; HEIGHT: 153pt" type="#_x0000_t75"><imagedata o:title="18-11" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image005.jpg"></imagedata></shape>
图18-12 设置服务类型
图18-13 添加IIS组件
在安装好IIS后,应该为要发布的Web服务建立一个虚拟目录,以方便调用,步骤如下:
(1)在控制面板中双击“管理工具”图标,打开“管理工具”窗口。
(2)在“管理工具”窗口中双击“Internet信息服务”图标,打开“Internet信息服务”窗口,如图18-14所示。
(3)在“默认站点”节点上单击鼠标右键,在出现的快捷菜单中,选择“新建”菜单项下的“虚拟目录”选项,打开“虚拟目录创建向导”对话框,如图18-15所示。
(4)单击“下一步”按钮,在出现的如图18-16所示的“别名”文本框中为虚拟目录指定一个名称“FoxWebService”,通过该名称可以引用一个硬盘上的实际物理目录。
(5)单击“下一步”按钮,在出现的如图18-17所示的“目录”文本框中指定一个存放Web服务内容的实际物理目录。
(6)单击“下一步”按钮,将出现如图18-18所示的设置目录权限画面,如图设置后,单击“下一步”按钮,在出现的画面中单击“完成”按钮,虚拟目录将被成功创建到“默认网站”节点中,如图18-19所示。
<shape id="_x0000_i1028" style="WIDTH: 194.25pt; HEIGHT: 152.25pt" type="#_x0000_t75"><imagedata o:title="18-12" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image007.jpg"></imagedata></shape> <shape id="_x0000_i1029" style="WIDTH: 193.5pt; HEIGHT: 141.75pt" type="#_x0000_t75"><imagedata o:title="18-13" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image009.jpg"></imagedata></shape>
图18-14 “Internet信息服务”窗口
图18-15 “虚拟目录创建向导”对话框
<shape id="_x0000_i1030" style="WIDTH: 193.5pt; HEIGHT: 141pt" type="#_x0000_t75"><imagedata o:title="18-14" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image011.jpg"></imagedata></shape> <shape id="_x0000_i1031" style="WIDTH: 193.5pt; HEIGHT: 141.75pt" type="#_x0000_t75"><imagedata o:title="18-15" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image013.jpg"></imagedata></shape>
图18-16 建立虚拟目录别名
图18-17 设置物理目录
<shape id="_x0000_i1032" style="WIDTH: 193.5pt; HEIGHT: 141.75pt" type="#_x0000_t75"><imagedata o:title="18-16" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image015.jpg"></imagedata></shape> <shape id="_x0000_i1033" style="WIDTH: 195pt; HEIGHT: 152.25pt" type="#_x0000_t75"><imagedata o:title="18-17" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image017.jpg"></imagedata></shape>
图18-18 设置目录权限
图18-19 虚拟目录添加完成后
可以使用Visual FoxPro的Web Service向导来创建和发布Web服务,步骤如下:
(1)选择Visual FoxPro Tools菜单中Wizards菜单项下的Web Service子菜单项,打开XML Web Services Publisher(Web服务发布器)对话框,如图18-20所示。在COM Server(COM服务程序)下拉选项框中选择要发布的.dll组件,如果组件没有包含在列表中,可以单击后面的省略(…)按钮进行选取。
(2)单击对话框中的Advanced(高级)按钮打开如图18-21所示的XML Web Service Location(Web服务位置)对话框,在Select Location下拉选择要发布的虚拟目录位置。
<shape id="_x0000_i1034" style="WIDTH: 178.5pt; HEIGHT: 75pt" type="#_x0000_t75"><imagedata o:title="18-18" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image019.jpg"></imagedata></shape> <shape id="_x0000_i1035" style="WIDTH: 218.25pt; HEIGHT: 108pt" type="#_x0000_t75"><imagedata o:title="18-19" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image021.jpg"></imagedata></shape>
图18-20 XML Web Services Publisher对话框
图18-21 XML Web Service Location对话框
(3)虚拟目录选择正确后,单击图18-21中的Select(选择)按钮,将打开可对Web服务的Options(选项)、Methods(方法)和Namespaces(命名空间)进行设置的对话框。具体设置分别如图18-22、图18-23、图18-24所示。完成后单击OK按钮返回到如图18-20所示的对话框。
(4)单击图18-20所示的Generate(生成)按钮将创建并发布Web服务,在Visual FoxPro生成Web服务的文件后,出现Web服务发布结果对话框,显示一个包含COM server、.WSDL文件、ISAPI或ASP 侦听的编译结果列表。如图18-25所示。
<shape id="_x0000_i1036" style="WIDTH: 185.25pt; HEIGHT: 166.5pt" type="#_x0000_t75"><imagedata o:title="18-20" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image023.jpg"></imagedata></shape> <shape id="_x0000_i1037" style="WIDTH: 185.25pt; HEIGHT: 166.5pt" type="#_x0000_t75"><imagedata o:title="18-21" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image025.jpg"></imagedata></shape>
图18-22 设置Web服务选项
图18-23 设置Web服务支持的方法
<shape id="_x0000_i1038" style="WIDTH: 185.25pt; HEIGHT: 166.5pt" type="#_x0000_t75"><imagedata o:title="18-22" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image027.jpg"></imagedata></shape> <shape id="_x0000_i1039" style="WIDTH: 190.5pt; HEIGHT: 102.75pt" type="#_x0000_t75"><imagedata o:title="18-23" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image029.jpg"></imagedata></shape>
图18-24 设置Web服务的命名空间
图18-25 Web服务发布结果
在Web服务发布成功后,将在图18-21的File Output Path(文件输出路径)文本框中指定的目录中生成3个文件(2个.wsml文件和一个.wsdl文件),在该示例中,所生成的文件是ChangeCustomer.WSDL、ChangeCustomer.wsml和ChangeCustomerClient.wsml。这3个文件都是XML文件,可以直接在浏览器或文本编辑器中查看。
当在IntelliSense中注册Web服务后,在书写有关已注册Web服务的程序代码时,IntelliSense可以随时进行代码输入提示。注册步骤如下:
(1)选择Visual FoxPro Tools菜单下的IntelliSense Manager菜单项,打开IntelliSense Manager窗口,如图18-26所示。
(2)单击Type页框中的Web Services按钮,在打开的对话框的WSDL URL Location(WSDL URL位置)文本框中输入所建立WSDL文件的URL,如图18-27所示。然后单击Register按钮进行注册。
<shape id="_x0000_i1040" style="WIDTH: 180.75pt; HEIGHT: 131.25pt" type="#_x0000_t75"><imagedata o:title="18-24" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image031.jpg"></imagedata></shape> <shape id="_x0000_i1041" style="WIDTH: 207pt; HEIGHT: 82.5pt" type="#_x0000_t75"><imagedata o:title="18-25" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image033.jpg"></imagedata></shape>
图18-26 IntelliSense Manager窗口
图18-27 指定WSDL URL并注册Web服务
在Visual FoxPro中可以通过SoapClient30对象调用Web服务,SoapClient30对象为客户端提供了一种通过SOAP协议发送请求到服务器端并处理服务器应答的高级接口。其使用方法如下:
oSoapClient=CREATEOBJECT("MSSOAP.SoapClient30") &&建立对象
在建立SoapClient30对象后,应该使用对象的MSSoapInit( )方法来初始化对象,在初始化期间,所有可在认证服务器(认证服务器在WSDL文件中指定)上的指定的操作将绑定SoapClient30对象,所以,这时就可以使用SoapClient30对象调用在服务器中定义的操作了。MSSoapInit( )方法的语法格式如下:
oSoapClient.MSSoapInit(WSDLFile,ServiceName,Port,WSMLFile)
参数说明如下:
WSDLFile
字符型。该参数是WSDL文件的URL,用于描述由服务器提供的服务,或者是包含在WSDL文件中的一个字符串。如果该参数的第一个字符是“<”,表示该参数值是一个WSDL字符串;否则,表示该参数值是一个WSDL文件。
ServiceName
字符型。可选的。该参数是在WDSL文件中的服务。如果忽略该参数、或为NULL、或为空字符串(""),在初始化SoapClient30对象时,则使用在WSDL文件中指定的第一个服务。
Port
字符型。可选的。该参数是在WSDL文件的端口名称,用来包含在SOAP请求信息中的指定操作。如果忽略该参数、或为NULL、或为空字符串(""),在初始化SoapClient30对象时,则使用在WSDL文件中指定的第一个端口。
WSMLFile
字符型。可选的。该参数是WSML文件的URL,在使用自定义类型映射程序时,该参数是必须的。
现在的问题是如何获得这些参数名称?使用浏览器或其他文本编辑器中打开所生成的WSDL文件,如图18-28所示。其中的service元素便是服务的名称,port元素是端口名称。
<shape id="_x0000_i1042" style="WIDTH: 337.5pt; HEIGHT: 40.5pt" type="#_x0000_t75"><imagedata o:title="18-26" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image035.jpg"></imagedata></shape>
图18-28 ChangeCustomer.WSDL文件片段
由于在该示例中只建立了一个服务,所以,可以只指定WSDLFile即可。例如,下面的语句可以Web服务调用在COM组件中的GetCustomerInfo( )方法来获得Customers表中数据。
oSoapClient=CREATEOBJECT("MSSOAP.SoapClient30")
oSoapClient.MSSoapInit("http://CCB-ZHJ/FoxWebService/ChangeCustomer.WSDL") &&初始化SoapClient30对象
cXML=oSoapClient.GetCustomerInfo() &&获得XML格式的Customers表中的数据
?cXML
新建一个如图18-29所示的表单。在“读取数据”按钮的Click事件中加入下列代码,用于从SQL Server数据库中读取信息,并在表格Grid1中显示出来。
oSoapClient=CREATEOBJECT("MSSOAP.SoapClient30")
oSoapClient.MSSoapInit("http://CCB-ZHJ/FoxWebService/ChangeCustomer.WSDL")
cXML=oSoapClient.GetCustomerInfo() &&获得XML格式的Customers表中的数据
RELEASE oSoapClient
SET MULTILOCKS ON
IF USED("curCustomer") &&关闭表
USE IN curCustomer
ENDIF
*!* 将XML转换为临时表
oXMLAdapter=CREATEOBJECT("XMLAdapter")
oXMLAdapter.LoadXML(cXML,.F.)
oXMLAdapter.Tables(1).Alias="curCustomer"
oXMLAdapter.Tables(1).ToCursor()
SELECT curCustomer
=CURSORSETPROP("Buffering",5)
*!* 设置表格
WITH Thisform.Grid1
.RecordSourceType=1
.RecordSource="curCustomer"
.ColumnCount=2
.Columns(1).Header1.Caption="客户编号"
.Columns(1).ControlSource="curCustomer.CustomerID"
.Columns(1).Width=80
.Columns(2).Header1.Caption="公司名称"
.Columns(2).ControlSource="curCustomer.CompanyName"
.Columns(2).Width=200
ENDWITH
Thisform.Refresh
在“发送更新”按钮的Click事件中加入下列代码,用于将Grid1中经过编辑的数据发送到SQL Server服务器并更新数据。
*!* 生成Diffgrams格式的XML文档<