关于c#下写的web service 服务在delphi下调用时的问题
首先我觉得有必要把.net平台下开发webservice进行一个比较全面的阐述,web service的最初产生是在电子商务的环境下出现的,有些问题通过传统的手段已经不容易解决,比如在应用程序之间进行商务通信、数据交换,使用dcom、corba等二进制机制的东西已经行不通了,姑且不说他们受各自平台的限制,比如dcom(distribute common objects model)只能在windows平台下进行,而corba(common objects request broker architecture)又只是java平台下的产物。他们要实现应用程序之间的数据通信是比较困难的。
在这种背景下,web services 应运而生,它很好的解决了跨语言、跨平台以及良好而安全的穿透企业防火墙。它的体系结构大体上分为五个层次:
http(hypertext transfer protocol)信道下进行数据通信
xml(extensable markup language)数据表达形式
soap(simple objects access protocol)的数据封装
wsdl(webservices description language)的描述语言格式
uddi(universal description and discovery integration) 统一的描述、发现和集成
作为它的优点跨语言、跨平台以及良好而安全的穿透企业防火墙已经足以使我们感到兴奋了。不过它也存在需要改善的地方,比如:
http进行数据通信存在速度较慢的情况,尤其是第一次联结。
需要一台web server这一额外的开销
说了webservices的体系结构以及其优点缺点以后我们切入正题,那就是我们这次讨论的话题:
web service 服务在delphi下调用时的问题
闲话少说,我们用一个检验webmethod的attribute的一个简单的例子进行阐述:它是完成一次从客户a转帐到b的一个简单商务过程。
首先我们在.net framework1.1下创建一个webservice,这时候.net会帮我们自动创建一个web应用
我们需要创建一个类attributetest,它是在命名空间namespace attributetesting下的,那么这个类它将自动继承了它的基类 system.web.services.webservice,需要支出的时,我们可以对这个web应用类设置其webserviceattribute,其中基本属性包括description 和namespace
[webserviceattribute(namespace="http://www.isdoo.com/services",
description="hello ansel,this is a testing web service!")]
public class attributetest : system.web.services.webservice
{
[webmethodattribute(description="描述信息:继承了count方法,并且对名称进行重载。执行的是把钱从a用户转帐到b用户……",
//messagename="changing messagename",
bufferresponse=true,
cacheduration=1000,
enablesession=true,
transactionoption=transactionoption.requiresnew)]
public string transmoney(double money)
{
try
{
contextutil.enablecommit();//transaction only used to database operation!
moneyintoa(money);
moneyoutfromb(money);
contextutil.setcomplete();
return "transaction successful,total "+money.tostring();
}
catch( exception e)
{
contextutil.setabort();
return "transaction failed! \n\r "+e.message;
}
}
private void moneyintoa(double money)
{
sqlcommand sqlcom = new sqlcommand("update budget set money=money+"+money.tostring()+" where name=a");
databaseaccess mydatabase = new databaseaccess();
sqlcom.connection=mydatabase.getconnection();
sqlcom.connection.open();
sqlcom.executenonquery();
sqlcom.connection.close();
//throw new exception("operation failed when transfer money into a!");
}
private void moneyoutfromb(double money)
{
sqlcommand sqlcom = new sqlcommand("update budget set money=money-"+money.tostring()+" where name=b");
databaseaccess mydatabase = new databaseaccess();
sqlcom.connection=mydatabase.getconnection();
sqlcom.connection.open();
sqlcom.executenonquery();
sqlcom.connection.close();
//throw new exception("operation failed when transfer money from b!");
}
}
其中我们需要特别注意的是,webmethodattribute,这也是我们这一次需要讲述的重点内容,只要给一个方法加上[webmethodattribute],哪怕里面没有任何属性,那么webservice就会把这个方法暴露(expose)给了客户段调用者.下面我们讲述一下它的6个属性,其中包括2个描述性的信息属性,4个功能属性
描述性的信息属性:
description
messagename
4个功能性属性:
bufferresponse
cacheduration
enablesession
transactionoption
其中我们需要注意messagename这个属性它delphi调用.net平台下开发的webservice的时候,如果你设置了messagename这个attribute的话,那么客户端调用时会报错误。这也许是一个bug,或许后面的版本会解决这个问题。至于这几个属性的具体功能就不再这里详细描述了。大家可以去看看相关的书籍。
下面我把delphi调用webservice的步骤列举一下:
首先如果你只是开发调用客户端,那么你只需要创建一个普通的应用程序即可,然后需要你做的是,在工具栏webservices下面找到soaphttpclient这个控件,然后把它放在你的客户端应用窗体上;
其次就是你需要设置这个soaphttpclient的属性url或者wsdl,这个内容就是你的webservice的服务地址
比如我们当前例子的服务地址是:http://localhost/attributetesting/attributetesting.asmx
如果你想输入wsdl那么就是http://localhost/attributetesting/attributetesting.asmx?wsdl
这样就完成了控件设置;
然后我们需要引入服务器端的wsdl,你可以手工来做,也可以用delphi提供的webservices importer功能来引入。
最后你只需要对引入的wsdl的接口进行调用即可。在这里我们的对应代码是:
procedure tform1.bitbtn1click(sender: tobject);
var
aa:attributetestsoap;//这个就是wsdl下的类接口对象
msg:widestring;
bb:double;
begin
//httprio2 其实就是所谓的代理类,它负责进行数据传输发送request和接受response的
aa:=httprio2 as attributetestsoap;
bb:=100.00;
msg:=aa.transmoney(bb);//这就是调用web服务所暴露给我们的web服务方法webmethod
showmessage(msg);
end;
ok! thats all!