65.9K
CodeProject 正在变化。 阅读更多。
Home

无需 Web 服务器即可进行 SOAP

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (14投票s)

2001 年 5 月 18 日

6分钟阅读

viewsIcon

411671

downloadIcon

5210

演示如何使用 ATL Server 在各种传输通道上构建 SOAP 服务器/客户端

引言

ATL Server 是 ATL 中用于创建 Web 应用程序和 Web 服务的一组新类。这些 Web 服务与用 C++、C#、VB 编写的客户端以及其他可以通过 SOAP 调用 Web 服务的工具完全兼容。对于此版本,ATL Server 中的 Web 服务支持仅限于通过 HTTP 传输进行调用。但是,与其他 ATL 组件一样,ATL Server 的设计非常灵活。您可能希望创建可以通过其他传输机制(如 TCP/IP)调用的 Web 服务,本文将帮助您解释如何更改 ATL Server 为 Web 服务支持的默认传输。文章包含两个示例:一个实现了可以通过 TCP/IP 调用的 Web 服务,另一个示例使用软盘作为传输介质。

本文展示了如何将 ATL Server 提供的 SOAP 支持与 ISAPI 框架分离,从而可以使用 ATL Server 在几乎任何通信通道上构建 SOAP 服务器和客户端。

摘要

服务器端

ATL Server Web 服务向导将生成通过 HTTP 公开的 Web 服务的代码。Web 服务实现为一个类,其声明如下:

[
request_handler(name="Default", sdl="GenSimpleSoapAppServiceSDL"),
soap_handler(
		name="SimpleSoapAppService", 
		namespace="urn:SimpleSoapAppService",
		protocol="soap"
	)
]
class CSimpleSoapAppService :
	public ISimpleSoapAppService

在此代码序列中,类声明之前的属性完成了大部分的公开工作。soap_handler 属性将注入以下方法:DispatchSoapCallParseSoapHeaders__AtlGetSDL。这些方法对于处理 SOAP 消息、将其映射到内部方法调用以及将内部方法调用的结果包装成 SOAP 响应是必需的。(Visual Studio .NET 7.0 Beta1 附带的 MSDN 库详细介绍了此属性注入的代码)。request_handler 属性使其能够处理 HTTP 请求。如果传输层不是 HTTP,则不再需要 request_handler 属性,因此可以将其注释掉。

atlsoap.h 中的 CSoapHandler<> 类旨在通过 HTTP 处理 SOAP 请求。处理 HTTP SOAP 请求的入口点是:

HTTP_CODE HandleRequest(AtlServerRequest *, IServiceProvider *)

请求正文和 SOAP 相关 HTTP 标头(“SOAPAction”)通过 AtlServerRequest* 参数的 pServerRequest (一个 ECB 包装器)成员从 ISAPI 扩展中检索。pServerRequest 对象提供了用于读取请求正文、读取 SOAPAction HTTP 标头以及将 SOAP 响应写回客户端的方法。由于目的是替换 HTTP 传输,我们需要找到另一种方式来启动 SOAP 请求处理,并为其提供执行相同操作的方法。

这可以通过创建一个 CSoapHandler 的派生类 CSoapTransportHandler 来解决,该类实现了以下入口点(可下载代码的 SoapTransportSrv.h 文件):

HTTP_CODE InvokeSoapMethod(stSoapTransportDescription	*pTransInfo) 

并且 stSoapTransportDescription 结构定义如下:

struct  stSoapTransportDescription
{
// the stream to write the SOAP response to
	IWriteStream     *pWriteStream;	
// the stream to read the SOAP request from
	IStream	         *pReadStream;
// the SOAP Action	
	CStringA          strSOAPAction;	 
// the service provider
	IServiceProvider *pServiceProvider; 
};

也许唯一需要详细说明的成员是 pServiceProvider。它允许 SOAP 服务器像 ISAPI DLL 中的服务一样共享服务。如果 SOAP 服务器不尝试使用它,则此成员可以为 NULL

现在,必须修改向导生成的 SOAP 服务器类以使用新的 CSoapTransportHandler 功能。新代码如下所示:

[
	//request_handler(name="Default", sdl= "GenSimpleSoapAppWSDL"),
	soap_handler(
		name="SimpleSoapAppService", 
		namespace="urn:SimpleSoapAppService",
		protocol="soap"
	)
]
class CSimpleSoapAppService :
	public CSoapTransportHandler<CSimpleSoapAppService>,
	public ISimpleSoapAppService
	...

向导生成的服务器代码中不再需要进行其他修改。

现在,可以实例化 SOAP 服务器,并且可以通过 CSoapTransportHandler::InvokeSoapMethod 调用 SOAP 方法,从而使用自定义流进行读取和写入,而不再依赖 ATL Server 的 HTTP 支持。

服务器的实例化由另一个类 CSoapDispatcher 处理,该类实现在 soapDispatch.h 文件中。CSoapDispatcher 类填充一个 stSoapTransportDescription 结构,然后实例化一个 SOAP 服务器并调用 SOAP 调用,如下所示:

	stSoapTransportDescription transInfo;
	// set the transInfo stream pointers
	...
	CComObjectNoLock<CSimpleSoapAppService> srv;
	HRESULT	hRet = S_OK;
	try
	{
		hRet = srv.InvokeSoapMethod( &transInfo );
	}
	catch(...)
...

此时,服务器应用程序只需:

  • 通过任何传输通道获取 SOAP 请求和 SOAP Action 标头
  • 将请求包装在 IStream 接口中
  • 提供一个 IWriteStream 来存储响应
  • 调用 CSoapDispatcher::DispatchCall
  • 将写流的内容(SOAP 响应)通过任何传输通道发送到客户端

客户端

sproxy.exe 生成的 SOAP 代理类的原型如下:

class CSimpleSoapAppService : public CSoapSocketClient
...

通过检查 sproxy.exe 生成的代码,可以发现代理类实际使用的 CSoapSocketClient 的方法/成员很少。这些是:

  • 构造函数
  • HRESULT SendRequest(LPCTSTR tszAction) throw()
  • void Cleanup() throw()
  • m_Stream,用作 IStream 接口,用于在发送前存储请求
  • m_ReadStream,用作 IStream 接口,用于在解析前存储响应

这里大部分工作由 SendRequest 方法完成。此方法旨在将 m_Stream 中的请求发送到 SOAP 服务器,并将服务器响应填充到 m_ReadStream 中。通过(在 sproxy.exe 生成的文件中)将 CSoapSocketClient 替换为包含所有这些方法和属性的自定义类,发送请求到 SOAP 服务器的实际通道仅取决于 SendRequest 方法的实现。

这正是附带的示例代码中的做法。为了重复使用 sproxy.exe 为不同传输类生成的代码,以下修改将非常有用:

template<TTransportClass>
class CSimpleSoapAppService : public TTransportClass
...

传输通道

示例实现了以下传输通道:

  • 通过存储介质上保存的文件进行通信(在 FloppyTransport 文件夹中)
  • TCP/IP 通信(在 TCPIPTransport 文件夹中)

每个传输通道实现都包含一个客户端应用程序和一个服务器应用程序。服务器使用 Include 文件夹中的 SOAP 服务器(其构建方式如上所述)。服务器应用程序中的代码仅负责传输。客户端应用程序仅实现特定于传输的类,作为 sproxy.exe 生成的修改类的 TTransportClass 参数。

请注意,上述修改仅允许通过自定义通道发送/接收 SOAP 消息。它们不允许检索服务的描述(SDL)。因此,TCPIPTransportFloppyTransport 示例的局限性在于,用于生成代理的 SDL 必须在示例之外生成。上面指定的应用程序中使用的 SDL 已保存为 Include 文件夹中的 simpleSoapSrv.wsdl。要获取服务器描述,需要通过向导创建 SOAP 服务器,完成接口,然后通过 ATL Server 提供的默认 HTTP 方式保存 SDL。

扩展:HTTPListenerTransport

此文件夹包含 TCPIPTransport 服务器的增强版本。此服务器监听指定的 TCP/IP 端口,但接受 HTTP 请求。它提供了一种响应 .disco 请求、生成已实现 SOAP 服务器的 SDL 以及接受 SOAP 调用的方法。此服务器可以提供一个非常轻量级的、完整的 SOAP 实现,而无需在计算机上安装 HTTP 服务器。要为此轻量级服务器创建客户端,只需使用 Visual Studio.NET 7.0 Beta1 IDE 中的 **添加 Web 引用** 向导,并将向导指向以下 URL:

http://<your_machine>:<ListenPort>/disco

如果构建 HTTPListenerServer 示例,URL 将变为:

https://:333/disco

为该服务器提供的 C# 客户端(HttpListenerCSharpClient)就是这样生成的。

最终考虑

要构建示例代码,只需解压缩源文件,然后加载并生成解决方案文件(ATLSSoapTransport.sln)。

从 Visual Studio .NET Beta2 开始,示例代码的更新版本将作为 ATL Server 示例包含在内。它将添加以下内容:

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.