haoxiaobo

从C到C++又到.net, 有一些心得, 和大家交流下...
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

VC非托管代码调用webservice,并支持代理服务器设置

Posted on 2012-01-09 22:49  HAL9000  阅读(744)  评论(0编辑  收藏  举报

这是这几天里我同时解决的另一个问题。

我用的是VC2003,在非托菅的本机代码中调用webservice时,很有一些令人糊涂的地方,在这里记下来,以后也方便自己回忆。

 方法:

1.增加webservice引用。

2.自动生成代理类。

上面简单。但当看着所生成的代理类时,多年没碰过VC代码的我哭了……VC的代理类是下面这样的:

 template <typename TClient = CSoapSocketClientT<> >

class CWebService1T : 
public TClient, 
public CSoapRootHandler
{
。。。

}

模板套模板。。。

嘛意思?

意思是:代理类在实例化时,要指定一个网络客户端工具类。默认这个类是CSoapSocketClientT<>, 这也是一个模板类。

template <typename TSocketClass = ZEvtSyncSocket>
class CSoapSocketClientT

{ 。。。}

看,默认的默认类是ZEvtSyncSocket,这是个啥类我实在没有心情去研究,看名字是一个Sock通讯类。不要不要!

那么调用webservice方法仲么办? 要这样:

 

 CWebService1T<CSoapWininetClient> proxy = new CWebService1T<CSoapWininetClient>;

proxy->SetUrl("http://xxx.com/Webservice1.asmx");  

proxy->HelloWork();

 

这里我没有用VC神经乎乎地推荐的那个 CSoapSocketClientT<ZEvtSyncSocket>, 而是用了CSoapWininetClient类做为工具类(atlsoap.h)。

注意上面的代码,有一个SetUrl的方法调用,这个方法你一定在代理类中找不到,但是编译运行又都正常。奇怪不? 

 请您这时候再回去注意一下CWebService1T的定义,CSoapWininetClient被置换为TClient泛型参数,而TClient又被放在了类定义的冒号后面,啥意思?

就是说你代入的这个模板参数类型将是代理类的父类呀!简直把人绕晕了!

 也就是说,我写CWebService1T<CSoapWininetClient> proxy 时,CSoapWininetClient将是CWebService1T<>的基类!CSoapWininetClient有SetUrl, SetProxy等方法,所以proxy 也就可以调用这些方法了。

因为 CSoapWininetClient是用了Wininet.dll库的api进行通信的,这个库的特点就是支持http,而且和ie的设置是相通的,因此,用了这个工具类,你的proxy对象就可以透过代理服务器调用webserivce了。

 

一切问题都解决了?没有。

 

我这两天遇上了几个做难死人的问题——一个客户的网络需要用代理服务器上网,而且是需要输入口令的。

本来这个问题也不是问题,只要ie能上网,在代理服务器要口令时,输入口令并选一下保存密码的复选框,这个用户凭据就会记录在系统中, CSoapWininetClient就可以自动取用,  很多客户的网络环境都是这样的,我们的客户端程序运行得很好。

但是不幸的是,这个客户的机器被设置了策略,就算是在ie里选了保存密码的复选框,密码也不能保存下来,每次打开ie时,都需要重新输入口令。

既然系统里没有用户凭据,CSoapWininetClient也就没有办法从ie得到用户名与口令。

 

我研究了CSoapWininetClient这个类,可恨的是这个类没有任何事件、callback、委托等扩展渠道让我在合适地地方切进去,设置那些代理啦、用户名啦口令啦什么的。在代理类调用hellowork时,就调用CSoapWininetClient的第一个方法就是SendRequest方法,在这个方法里,它打开对话,建立连接,Post数据、得到回应的流,一气呵成了!中间没有用户的机会加入代码。

 

我发愁了老半天,决定从 CSoapWininetClient派生一个子类来用,想试试能不能通过重载一下某些方法来介入自己的代码。这叫什么模式来着?装饰类?

 

结果发现这个类里很多粉重要的方法、成员都是private的,没法引用。

 

真没有办法了?我暴怒了!我和他拼了!我把 CSoapWininetClient类的源代码全拷贝出来,在项目里建了一个新类,叫CFuckedSoapWininetClient, 然后把CSoapWininetClient类的所有内容都复制了进去,现在,你是我的啦!哇哈哈!

 

再把调用Webservice的代码改一下,把参数类名改为Fuck过的新类。

 CWebService1T<CFuckedSoapWininetClient> proxy = new CWebService1T<CFuckedSoapWininetClient>;

proxy->SetUrl("http://xxx.com/Webservice1.asmx");  

proxy->HelloWork(); 

编译,通过。运行,通过!


现在,通信类是我的了,任我哪啥了!想加代理服务器支持,那是易如翻掌了。

 

有关 代理服务器支持 功能的实现,请参考另一篇文章 http://www.cnblogs.com/haoxiaobo/archive/2012/01/09/2317559.html