Using OpenAPI with C++[1] _VC调用WebService

 

Web2.0时代中,C++也照样演绎着它经久不衰的生命力。很多人认为C++做网络通信开发等等太傻,虽然我不得不承认它的WebServices通信程序开发速度不如C#,C#中很多忽略的细节,在C++中全部需要自己进行定义,但是它也不是不可以做,下面跟随笔者来一起学习使用C++调用OpenAPI的方法吧。

1、 你需要的东西

其实系统中早就已经存在了SOAP的接口,XP下的是1.0版本,组件位置在C:/Program Files/Common Files/MSSoap/Binaries/MSSOAP1.dll,C是系统盘符。其实调用OpenAPI,系统里面自带的Soap1.0组件就已经足够了,微软现在官方提供3.0的Soap SDK,对我们意义不大,接口名称后面都加了”30”,最值得一提的是3.0的Soap SDK中提供的Trace Utility,这个工具可以方便我们调试。

你还需要XML解析器的支持,也就是系统里面的MSXML组件,这个想必大家都知道吧。只需要import进来,然后using namespace 就可以使用其中的接口了。

 

2、 了解对方的OpenAPI声明

我们这里以CSDN的OpenAPI做范例进行讲解。他们的一个讲解页面是http://community.csdn.net/openapi/openapiexplain.htm,是用C#作为主要语言,没关系,我们打开http://forum.csdn.net/OpenApi/forumapi.asmx,能看到ForumAPI提供了7个API。我们先看GetUserProfile,获取用户信息的这个API,我们能看到发送的XML的格式为如下:

 

POST /OpenApi/forumapi.asmx HTTP/1.1

Host: forum.csdn.net

Content-Type: text/xml; charset=utf-8

Content-Length: length

SOAPAction: "http://www.csdn.net/GetUserProfile"

 

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

  <soap:Body>

    <GetUserProfile xmlns="http://www.csdn.net/">

      <identity>

        <username>string</username>

        <password>string</password>

      </identity>

      <username>string</username>

    </GetUserProfile>

  </soap:Body>

</soap:Envelope>

 

报头部分只需要注意一个地方,SOAPAction的值即可

 

Xsi、xsd和soap则可以理解成Envelope 的3个属性。<soap:Body>里面的是body,是我们需要发送的内容,<GetUserProfile xmlns="http://www.csdn.net/">和</GetUserProfile>之间就是数据了,GetUserProfile是函数名,http://www.csdn.net/是名称空间(Namespace)。函数名也能算是一个Element(元素),而XML中,元素之间嵌套元素,也就是Element里面还有Element。你认为<identity>也是一个元素吗?对,是的。不过,它里面又有个两个元素username和password,而identity元素和下面那个username是平级的,我们C++伪代码是不是可以这么写?

struct GetUserProfile

{

       struct identity

       {

              string username;

              string password;

       }

       string username;

}

我们现在已经摸清了发送的XML格式了,该怎么工作呢?

首先

#import <msxml3.dll>

using namespace MSXML2;

 

#import "C:/Program Files/Common Files/MSSoap/Binaries/MSSOAP1.dll" /

       exclude("IStream", "ISequentialStream", "_LARGE_INTEGER", /

       "_ULARGE_INTEGER", "tagSTATSTG", "_FILETIME")

using namespace MSSOAPLib;

将两个关键的组件包含进来。

接下来

CoInitialize(NULL); //初始化COM对象

       //定义如下三个接口对象

       ISoapSerializerPtr Serializer;

       ISoapReaderPtr Reader;

       ISoapConnectorPtr Connector;

//创建Connector对象实例

       Connector.CreateInstance(__uuidof(HttpConnector));

       Connector->Property["EndPointURL"] = "http://forum.csdn.net/OpenApi/forumapi.asmx";

//这个是写提供服务的URL,EndPointURL这个属性

       Connector->Connect();//连接

       // 开始消息

       Connector->Property["SoapAction"] = "http://www.csdn.net/GetUserProfile";

       Connector->BeginMessage();

       // 创建SoapSerializer对象实例

       Serializer.CreateInstance(__uuidof(SoapSerializer));

       // 将serializer连接到connector的输入字符串

       Serializer->Init(_variant_t((IUnknown*)Connector->InputStream));

//下面个属性设置好,前面讲过的

 

       Serializer->startEnvelope("SOAP","http://schemas.xmlsoap.org/soap/envelope/","");

//开始Envelope

       Serializer->SoapAttribute("xsi", "", "http://www.w3.org/2001/XMLSchema-instance", "xmlns");

       Serializer->SoapAttribute("xsd", "", "http://www.w3.org/2001/XMLSchema", "xmlns");

Serializer->startBody("");  //<soap:Body>

//开始GetUserProfile元素

       Serializer->startElement("GetUserProfile","http://www.csdn.net/","NONE",""); //<GetUserProfile xmlns="http://www.csdn.net/">

 

       Serializer->startElement("identity","http://www.csdn.net/","NONE","");//<identity>

 

       Serializer->startElement("username","http://www.csdn.net/","NONE","");

      

       Serializer->writeString("tr0j4n"); //笔者的CSDN用户名

       Serializer->endElement();

 

       Serializer->startElement("password","http://www.csdn.net/","NONE","");  Serializer->writeString("1Z3azg5W78dsq"); //笔者的CSDN密码

       Serializer->endElement();

 

       Serializer->endElement(); //</identity>

 

       Serializer->startElement("username","http://www.csdn.net/","NONE","");

       Serializer->writeString("tr0j4n"); //需要查询的CSDN ID的用户信息

       Serializer->endElement();

 

       Serializer->endElement();//</GetUserProfile>

//结束GetUserProfile元素

 

       Serializer->endBody();//</soap:Body>

 

       Serializer->endEnvelope();//结束Envelope

       Connector->EndMessage();//结束消息

 

上面的startElement和endElement是开始元素和结束标志的时候使用的,你看出了上面的代码中各个元素之间的嵌套和并列关系了么?我已经在后面注释中和对应的XML进行了对应,您还可以参考前面的那段伪代码。WriteString是向所在的元素中写入值,注意在startElement的时候不要忘了加上Namespace的字符串。

 

经过上面的代码,您就把那段标准格式的请求发出去了,如果您的程序出现问题,在Connector->EndMessage();这一句程序抛出异常,请检查你前面的startElement和endElement函数的使用情况,是不是有配对没有弄好,切记,这是很多人提出来的问题。

 

接下来我们需要接受服务器返回的信息,先看下服务器回显的XML格式如下:

 

HTTP/1.1 200 OK

Content-Type: text/xml; charset=utf-8

Content-Length: length

 

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

  <soap:Body>

    <GetUserProfileResponse xmlns="http://www.csdn.net/">

      <GetUserProfileResult>boolean</GetUserProfileResult>

      <profile>

        <point>int</point>

        <techExpertPoint>int</techExpertPoint>

        <topForums>

          <TopForum>

            <forumId>guid</forumId>

            <expertPoint>int</expertPoint>

            <rank>string</rank>

          </TopForum>

          <TopForum>

            <forumId>guid</forumId>

            <expertPoint>int</expertPoint>

            <rank>string</rank>

          </TopForum>

        </topForums>

        <nonTechExpertPoint>int</nonTechExpertPoint>

        <nickName>string</nickName>

        <username>string</username>

      </profile>

      <error>

        <errId>int</errId>

        <errInfo>string</errInfo>

        <description>string</description>

      </error>

    </GetUserProfileResponse>

  </soap:Body>

</soap:Envelope>

 

我们来写获得服务器返回XML信息的代码:

 

       // 创建Reader实例

       Reader.CreateInstance(__uuidof(SoapReader));

 

       // 将reader联接到connector的输出字符串

       Reader->Load(_variant_t((IUnknown*)Connector->OutputStream), "http://www.csdn.net/GetUserProfile");

 

 

       我们看下ISoapReaderPtr接口的获得返回值的两个方法,一个是RPCResult,MSDN的解释是This property returns the first child element of the first entry in the <Body> element of a SOAP message.还有个是RPCStruct,This property returns the first entry in the <Body> element of a SOAP message.

 

我们看上面的返回的XML的内容,看到<GetUserProfileResult>boolean</GetUserProfileResult>了没?那是不是FirstChild呢?first entry in the <Body> element of a SOAP message。所以我们只需要Reader->RPCResult->text不就能获得GetUserProfileResult这个值了吗,如果其他的元素您不关心的话,你完全可以将其转换成char *输出成功与否即可。这就是你为什么在Google上能搜索出一堆C++调用WebServices的文章其中的代码都几乎一样,有printf("Return Message is : %s/n",(const char*)Reader->RPCResult->text);这句话的原因,但是那些文章都很不负责任,它就没有想过我们需要其他的元素的值了吗?

 

文章出处:http://blog.csdn.net/tr0j4n/article/details/4967118

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值