使用 Visual FoxPro提供一个基于互联网的数据服务

本文介绍了如何使用Visual FoxPro通过XML来提供基于互联网的数据服务。程序生成XML,发送到指定URL,服务器处理请求并以XML形式返回结果。客户端接收并解析响应,处理可能的错误和返回值,包括游标操作。整个过程涉及SQL命令执行和XML编码。
摘要由CSDN通过智能技术生成
 
Rick Strahl写的关于使用VFP构建基于Web的DataService,很好的为我们阐述了整个DataService的数据流程,不管你是使用何种方法构建Webservice的,这篇文章在架构上都有指导意义.花了整整两天翻译,希望与大家共享,水平有限,不当之处请大家指出.
使用 Visual FoxPro提供一个基于互联网的数据服务

Source Code:
http://www.west-wind.com/presentations/foxwebDataService/FoxWebDataService.zip

你有没有想过在你的程序中建立这样一种远程数据访问机制:你将不仅可以从本地网络中访问数据,而且可以从
Web上轻易的访问数据。你仅仅需要做的是指向一个URL,并且执行一些Sql语句,那么客户端中就可以得到你需要的数据了,这是不是很Cool?在以下这篇文章中,Rick将会为我们展示怎样利用Visual FoxPro做到这一切的。
 
如果你正在使用任何一种类库,你也许知道其中关于数据访问的那些类。他们都不约而同的都提供了访问不同数据源的方法,一个标准的数据访问层会提供针对某一类型的数据源执行各种SQL语句的功能。数据访问层总是使用不同的数据连接器(data connector)来访问数据源,有时使用VFP的SQL命令或任何DML类型的SQL命令,有时使用SQLPassthrough或OleDb或CursorAdapter等较低级别的数据连接器。
 
在这篇文章中,我编写了一些有关数据访问的类,以便提供一个可以和Web XML Service进行通信的接口。这个项目分为两部分:1.一个类似代理的客户端,他负责通讯中请求(Request)的编码与响应(Response)的解码。2.一个服务器端,他负责通讯中请求的解码,逻辑的执行与响应的编码。所有的消息(Message)我们都使用XML格式。这个项目需要你的Web服务器可以执行Visual FoxPro代码,类似于Asp+COM,Web connection,Active FoxPro Page,FoxISAPI。我将在一开始使用Web Connection(因为他比较简单易用),最后我将使用ASP+COM的方式来实现。
Web based SQL access
第一步我们需要建立Sql 代理与服务器端。我们这样做的目的是让Sql代理可以以XML的方式传递Sql命令和一些指令给服务器端上的程序进行处理,注意,Sql代理发送的请求(request)与服务器端的响应(Response)都是以XML形式传递的。
 
我现在要建立一个简单的类,其中只有一个方法(Method)—Execute()用来传送Sql命令。这个方法与VFP中的SQL Passthrough的SQLExecute十分类似,并且他们都返回同一类型的值。
 
如果你考虑使用VFP来实现这个类将会简单的多,因为VFP提供了许多工具可以帮助我们。在VFP中我们有一个动态执行引擎(Macros和Eval)或SQL Passthrough来执行我们的命令 ,我们还有CUSORTOXML和XMLTOCURSOR等XML转换工具。我们唯一需要做的就是规定一种XML消息格式, 用以在Client与Server之间传递。
 
在Client端只有一个用来处理XML消息的代理类,他将你的Sql命令转换为XML,并以请求的形式发给Server进行处理。Server处理你发来的SQL命令,并将结果以XML的形式发回给Client。Client将发回的XML解码为游标(cursor),错误信息或返回值。图一为我们解释了这个过程:
 图一:wwwHTTPSql类将Sql命令传递给Web服务器,由Web 服务器上的wwwHTTPSqlServer进行处理并将结果返回给Client。
 
Client与Server之间的通信是通过wwwHTTPSql类与wwwHTTPSqlServer类来实现的。wwwHttpSqlServer类可以集成在任何支持VFP的Web程序中,比如Web Connection ,ASP,FoxISAPI,Active FoxPro Page,ActiveVFP等.但你必须保证wwwHttpSqlServer在Web 服务器上运行,以便Client进行连接。
 
XML通过字符或DOM节点的形式传递,所以他十分适合在不同的环境中工作。图一向我们展示了wwwHTTPSql与wwwHTTPSqlServer类之间的关系。
  
在我深入讲解之前,让我们快速浏览一下Client上的代码,Client使用wwwHttpSql类来和特定Url上的Web Server进行连接并获取数据的。
Listing 1: Running a remote SQL Query with wwHTTPSql
DO  wwHTTPSQL  && Load Libs
 
oHSQL = CREATEOBJECT("wwHTTPSQL")
oHSQL.cServerUrl = "http://www.west-wind.com/wconnect/wwHttpSql.http"
oHSQL.nConnectTimeout = 10
 
*** Specify the result cursor name
oHSQL.cSQLCursor = "TDevelopers"
 
*** Plain SQL statements
lnCount = oHSQL.Execute("select * from wwDevRegistry")
IF oHSQL.lError
   ? oHSQL.cErrorMsg
ELSE
   BROWSE
ENDIF
 
这段程序中你需要注意的是:1.你需要访问的Web Server(在这里我们使用Web Connection Server)的Url的设定 2:你传递的Sql命令。这些都是最基本的设定,因为wwwHttpSql继承自wwwHttp类,所以我们还可以设定一些诸如验证,连接等功能。
 
Client可以通过nResultModel属性设置返回数据的方式,默认(nResultModel=0)是返回VFP游标,nResultModel=2表示以XML的形式返回,此时cResponserXML的值为XML。nTransportMode属性让你选择数据传送的方式, nTransportMode=1表示使用VFP的CURSORTOXML命令,nTransportMode=0表示使用XML格式,nTransportMode=2表示使用二进制格式(Binary)(与VFP Cursor比较起来,如果数据量较大的话,使用二进制格式会更有效率)。简而言之,你可以适当的配置这些属性,使你在任何情况下更有效的处理数据。
 
Execute方法用以执行Sql命令,wwwHttpSql类将会知道返回的是游标或XML消息或任何其他值,他还会捕捉错误与处理返回的XML响应。Client 与Server端其实只是处理XML消息,所以我们只需要任何方法拼凑出合适的经过验证的XML消息发给已知URL的Web Server,而没必要一定使用VFP,比如我们可以在.Net中将将Dataset解析为XML。
 
Client端生成如下的XML消息发送给Server。
<wwhttpsql>
   <sql>select * from wwDevRegistry</sql>
   <sqlcursor>TDevelopers</sqlcursor>
   <transportmode>1</transportmode>
</wwhttpsql>
 
当client上执行Execute()命令时,会执行以下步骤:
    1. 根据你在程序中设置的属性,生成如上的XML。
    2. XML被发送到指定的Url。
    3. Server端处理请求并返回XML形式的结果。一般来说,结果都是以XML形式返回的,除非发生了硬件错误,而软件错误也会以XML形式返回。
    4. Client收到响应信息并进行解析。
    5. 首先会验证响应信息是否为XML形式的,如果不是,则产生一个错误(Error),请求失败。
    6. 如果响应信息中包含错误的XML节,则请求失败,将错误信息赋值给IError和CErrorMSg。
    7. 如果响应的XML信息中包含一个返回值,那我们将他赋值给VReturnValue。
    8. 如果在响应的XML信息中包含一个游标并且nResultMode=0,我们将游标赋值给cSQLCursor属性。
 
如果你回想一下这个过程,你就会发现,在VFP和wwXML class类的帮助下,我们只需要很少的代码就可以完成上述功能,下面就是wwwHttpSql的核心代码,我们来看一下: 
Listing 2: The core code of the wwHTTPSql client class
***********************************************************
* wwHTTPSQL :: CreateRequestXML
****************************************
FUNCTION CreateRequestXML()
LOCAL lcXML
 
loXML = THIS.oXML
lcXML = ;
"<wwhttpsql>" + CRLF + ;
loXML.AddElement("sql",THIS.cSQL,1) + ;
loXML.AddElement("sqlcursor",THIS.cSQLCursor,1) + ;
IIF(!EMPTY(THIS.cSQLConnectString),;
    loXML.AddElement("connectstring",THIS.cSQLConnectString,1),[])  +;
IIF(!EMPTY(THIS.cSkipFieldsForUpdates),loXML.AddElement("skipfieldsforupdates",;
    THIS.cSkipFieldsForUpdates,1) +CRLF,[]) + ;   
IIF(THIS.nTransportMode # 0,;
loXML.AddElement("transportmode",THIS.nTransportMode,1),[]) +;
IIF(THIS.nSchema = 0,loXML.AddElement("noschema",1),[]) +;
IIF(!EMPTY(THIS.cSQLParameters),CHR(9) + "<sqlparameters>" + CRLF + ;
                                THIS.cSQLParameters + ;
                                CHR(9) + "</sqlparameters>" + CRLF,"")
 
IF THIS.lUTF8
   lcXML = lcXML + loXML.AddElement("utf8","1",1)
ENDIF
                               
lcXML = lcXML + "</wwhttpsql>"
 
THIS.cRequestXML = lcXML
 
RETURN lcXML
 
**********************************************************************
* wwHTTPSQL :: Execute
****************************************
FUNCTION Execute(lcSQL)
LOCAL lnSize, lnBuffer, lnResult, llNoResultSet, lcXML
 
lcSQL=IIF(VARTYPE(lcSQL)="C",lcSQL,THIS.cSQL)
THIS.cSQL = lcSQL
 
THIS.lError = .F.
THIS.cErrorMsg = ""
 
IF !INLIST(LOWER(lcSQL),"select","create","execute")
   llNoResultSet = .T.
ELSE
   llNoResultSet = .F.
ENDIF
 
*** Create the XML to send to the server
lcXML = THIS.CreateRequestXML()
 
THIS.nHTTPPostMode = 4 && Raw XML
THIS.AddPostKey("",lcXML)
 
THIS.cResponseXML = THIS.HTTPGet(THIS.cServerUrl,;
                                 THIS.cUserName,THIS.cPassword)
 
*** Clear the entire buffer
THIS.AddPostKey("RESET")
THIS.AddSqlParameter() 
 
IF THIS.nError # 0
   THIS.lError = .T.
   RETURN -1
ENDIF
 
THIS.nResultSize = LEN(THIS.cResponseXML)
 
IF EMPTY(THIS.cResponseXML)
      THIS.cErrorMsg = "No data was returned from this request."
      THIS.nError = -1
      THIS.lError = .T.
      RETURN -1
ENDIF
 
RETURN this.ParseResponseXml()
 
 
************************************************************************
* wwHttpSql :: ParseResponseXml
****************************************
FUNCTION ParseResponseXml()
LOCAL lcFileName, loDOM, loRetVal, cResult, ;
      loError, loSchema, loXML
 
loXML = this.oXml
 
loDOM = loXML.LoadXML(THIS.cResponseXML)
THIS.oDOM = loDOM
 
*** Check for valid XML
IF ISNULL(loDom)
      THIS.cErrorMsg = "Invalid XML returned from server" +;
                       loXML.cErrorMsg
      THIS.nError = -1
      THIS.lError = .T.
      RETURN -1
ENDIF
 
*** Check for return value
loRetVal = loDom.documentElement.selectSingleNode("returnvalue")
IF !ISNULL(loRetval)
   THIS.vReturnValue = loRetVal.childnodes(0).Text
ENDIF
 
*** Check for results that don't return a cursor
lcResult = Extract(THIS.cResponseXML,"<result>","</result>")
IF lcResult = "OK"
   RETURN 0
ENDIF
 
*** Check for server errors returned to the client
loError = loDom.documentElement.selectSingleNode("error")
IF !ISNULL(loError)
   THIS.cErrorMsg = loError.selectSingleNode("errormessage").text
   THIS.nError = -1
   THIS.lError = .T.
   RETURN -1
ENDIF
 
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值