简介
Microsoft? .NET 框架和 Microsoft? Visual Studio.NET 利用 xml 和 SOAP 技术,使开发人员能够创建广泛的解决方案。
SOAP 是一个简单、轻便、并在业界获得广泛支持的协议,适用于各种各样的应用,它与 .NET 框架的结合简单而合乎自然。
从底层开始,SOAP 的设计目标就是使之成为一种非常简单的协议,能够以各种不同的方式满足各种不同的需求。除了 Microsoft,已有许多公司实际应用 SOAP,例如 IBM、Develop Mentor 和 Userland。
在使用 SOAP 的体系中,有若干种要害技术。在创建基于 SOAP 的解决方案时,每种技术都会解决开发人员的一些共同问题。这些技术分别属于 .NET Remoting、asp.net Web Services 和 ATL Web Services,它们具有许多共同的技术特点:
用于消息生成和使用的 XML。
符合 SOAP 1.1 规范,包括第 5 节 SOAP 编码,这使 SOAP 应用之间具有很好的互操作性。
XML 保真性(非第 5 节 SOAP 编码),用于完全断开的模型。
WSDL(XML 方案的一种形式),用于提供说明。
可用无状态编程模型扩展系统。
使用 Visual Studio.NET 的良好开发环境。
ASP.NET Web Services 和 .NET Remoting 还共享下列技术:
XCOPY 系统部署。
System.Net,进行网络通讯时,无论在服务器还是客户端它都运行良好。
公共语言运行时可在受控代码和线程缓冲池中重用。
提供强大的 SOAP 支持,例如 SOAP 头和单向消息等特性。
能够与 C#、Visual Basic.NET 或任何符合 CLS 规范的语言(如 Cobol、Python、 ComponentPascal 等等)配合使用来编写应用程序。
除了以上列出的共同特点和技术以外,ASP.NET Web Services、.NET Remoting 和 ATL Web Services 还分别为开发人员提供了许多特有的功能,下面这些内容有助于开发人员在生成应用程序时把握正确的方向。
假如您要生成 .ASP 应用程序,ASP.NET Web Services:
答应与 ASP.NET HTTP 运行时紧密集成。
鼓励开发人员着重于运用 XSD 数据类型来提供给用程序。
在 Visual Studio.NET 中提供强大的设计支持。
假如您要生成 MTS/COM+ 应用程序,.NET Remoting:
提供全面的受控代码类型系统的网络保真性。
提供在网络上通过引用来传递对象的功能,并且可返回到特定进程中的特定对象。
提供二进制通讯能力。
假如您要生成 ATL/C++ 应用程序,ATL Server:
提供灵活并且可控的本机 (C++) 解决方案。
建立于 ATL Server ISAPI Web 应用体系机构之上(利用线程缓冲池、缓存,等等)。
将 SOAP 用作 Web 开发工具
ASP.NET Web Services 提供了 RAD 方式,以供快速创建和使用 Web 服务。这些服务宽松地组合在一起,并可与 ASP.NET 高度集成。ASP.NET Web Services 是 Web 开发人员在 Internet 上提供 Web 服务的首选方法,它的目标是提供快速、简便、性能优越的 SOAP 服务。
ASP.NET Web Services 可以和 ASP.NET HTTP 引擎深入集成,这使得熟悉 Microsoft Web 开发技术的开发人员能够方便地生成和使用基于 SOAP 的 Web 服务。
ASP.NET 以 .asmx 文件提供对 Web Services 的支持。.asmx 文件是与 .aspx 文件相似的文本文件。这些文件可以是包含 .aspx 文件的 ASP.NET 应用程序的一部分。它们可以使用 URI 寻址方式,这和 .aspx 文件相同。
以下是一个非常简单的 .asmx 文件示例:
<%@ WebService Language="C#" Class="HelloWorld" %>
using System;
using System.Web.Services;
public class HelloWorld : WebService {
[WebMethod] public String SayHelloWorld() {
return "Hello World";
}
}
这个文件以 ASP.NET 指示的 Web Service 开始,并将语言设置为 C#(也可以将语言设置为 Microsoft Visual Basic?、C 或大约 30 种第三方语言中的任何一种)。然后,它将导入名称空间 System.Web.Services。这个名称空间是必要的,您必须在文件中包括它。下一步,声明 HelloWorld 类。这个类从基类 WebService 导出。最后,任何要作为服务的一部分来访问的方法在它们的签名之前将具有自定义属性 [WebMethod],在 Visual Basic 中则为“<WEBMETHOD()>”。
要使这个服务生效,可以将文件命名为 HelloWorld.asmx,然后将它放在虚拟目录 Bar 中的服务器 Foo 上。使用几乎任何兼容 Html 3.2 或更高版本的浏览器,都可以输入 URL http://Foo/Bar/HelloWorld.asmx 来显示这个 Web Service 的公用方法(标有 WebMethod 属性),以及那些可用来调用这些方法的协议,例如 SOAP 或 HTTP GET。假如在 Internet EXPlorer 地址栏中输入 http://Foo/Bar/HelloWorld.asmx?SDL,基于服务说明语言 (WSDL) 语法,将产生与 XML 文件相同的信息。这个 WSDL 文件由访问服务的客户使用,并且非常重要。
访问 Web Serivces
除了使开发人员能够创建 Web Services 的技术之外,Microsoft .NET 框架还提供了一套用来“使用”(即以客户端身份访问)Web Services 的成熟工具与代码。因为 Web Services 基于简单对象访问协议 (SOAP) 和 HTTP 等开放协议,所以这种客户端技术也可以用于使用非 ASP.NET Web Services。
SDK 中有一种称为 WebServiceUtil.exe 的工具(在 VS IDE 中使用“Add Web Reference...”选项时自动生效)。这个程序可用于下载 Web Service 的 WSDL 说明,然后创建表示这个服务的地址的代理类。例如,您可以输入:
WebServiceUtil /c:PRoxy /pa:http://someDomain.com/someFolder/HelloWorld.asmx?SDL
然后,系统将创建称为 HelloWorld.cs 的代理类。
这个类与前面创建的类看起来非常相似。它包括称为 SayHelloWorld 的方法,该方法返回字符串。将这个代理类编译到应用程序中,然后调用其方法,结果是代理类在 HTTP 上打包 SOAP 请求,并接收 SOAP 编码的回应,然后封送为一个字符串。
从客户端来看,代码非常简单:
Dim myHelloWorld As New HelloWorld()
Dim sReturn As String = myHelloWorld.SayHelloWorld()
返回值将是“Hello World”。
将 SOAP 用作组件开发工具
创建分布式应用程序时,假如需要高度控制性并要求能够选择系统耦合程度,那么可以使用 Microsoft .NET Remoting。
Microsoft .NET Remoting 还提供了与公共语言运行时的深入集成,并且为开发人员提供了全面的跨连接类型系统保真性。这包括构造函数、委托、重载方法、通过值和引用传递对象、类的层次结构、接口、方法、属性、字段,以及通过可插入通道、分布式标识、激活、租用生存期和 CallContext(独立于参数的 SOAP 头中的流对象)在连接上的应用程序 (Web Services) 之间进行 Marshal by Value(制作副本)以及 Marshal by Ref(传递 ObjRef)。
使用 .NET Remoting,开发人员可以从任何进程提供 Remoting 终结点,包括控制台应用、GUI 应用、NT Service 和 IIS。在任何使用有效加载编码(在产品中提供了可插入序列化格式化程序以及 SOAP 和二进制格式化程序)通过可插入通道进行的任何传输过程中都会出现这种情况。SOAP=HTTP+XML,同时完全支持 HTTP 和 SMTP 上的 SOAP 1.1,这十分令人满足。
我们可以获得 WSDL 支持来说明 Web Service 并保证运行时类型系统的完全保真性。.NET Remoting 提供了 .NET SDK 的 Soapsuds 工具,可以从元数据生成受控类和 COM 对象的服务说明。Soapsuds 工具也使用服务说明并生成元数据和代理。开发人员可以使用密集侦听模型,将自己的操作作为应用程序入站和出站消息流插入。想更为深入的开发人员则可以采用使用套接字的二进制编码 TCP 通道。
.NET Remoting 使受控组件、本机 COM/COM+ 组件以及接受服务的组件(使用 COM+ 服务的受控组件)远程化。SOAP、二进制以及任何一种可插入通道和格式上都可能出现这些情况。
样例:SOAP 受控代码事件
下列代码演示如何在两个应用程序之间引发受控代码事件。客户端有一个本地对象,注册为接收远程对象的事件通知。客户端呼叫服务器对象时,就引发事件,产生对客户端本地对象的回叫。
服务器端
zap.cs
using System;
namespace Zap
{
// 定义事件参数
public class GreetingEventArgs : EventArgs
{
public GreetingEventArgs(string greeting)
{
this.greeting = greeting;
}
public string greeting;
}
// 定义事件
public delegate void GreetingEvent(object sender,
GreetingEventArgs e);
// 定义服务
public class Waz : MarshalByRefObject
{
// 客户端将预定和取消预定此事件
public event GreetingEvent Greeting;
// 由客户端远程调用的方法
public void HelloMethod(string greeting)
{
Console.WriteLine("Received String {0}", greeting);
// 将字符串打包到 GreetingEventArgs 中
GreetingEventArgs e = new GreetingEventArgs(greeting);
// 引发事件
if (Greeting != null)
{
Greeting(this, e);
}
}
}
}
host.cs
using System;
using System.IO;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;
public class Host
{
public static void Main(string[] args)
{
// 手动加载 http 通道。
// 这也可以在 Remoting 配置文件中完成。
ChannelServices.RegisterChannel(new HTTPChannel(999));
// 注册服务器类型。
// 这也可以在 Remoting 配置文件中完成。
RemotingServices.RegisterWellKnownType(
"Zap", // 程序集
"Zap.Waz", // 完整的类名
"host/Waz.soap", // URI
WellKnownObjectMode.Singleton); // 对象模式
// 完成操作,等候用户退出
Console.WriteLine("主机已经预备好处理远程消息。");
Console.WriteLine("请按 ENTER 键退出");
String keyState = Console.ReadLine();
}
}
客户端
client.cs
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.HTTP;
using Zap;
// 将对象按引用本地封送到要引发的事件
public class Baz : MarshalByRefObject
{
public void GreetingHandler(object sender, GreetingEventArgs e)
{
Console.WriteLine("GreetingHandler 回叫: 问候: {0}\n",
e.greeting);
}
}
public class Client
{
public static void Main(String[] args)
{
Baz baz = new Baz();
// 这也可以在 Remoting 配置文件中完成。
// 注册 HTTP 通道
ChannelServices.RegisterChannel(new HTTPChannel(0));
// 获取 SOAP URL 代理
Waz waz = (Waz)Activator.GetObject(
typeof(Waz),
"http://localhost:999/host/Waz.soap"
);
// 预定事件: 通过 SOAP 进行
waz.Greeting += new GreetingEvent(baz.GreetingHandler);
for (int i = 0; i < 5; i++)
{
// 通过 SOAP 向 waz 发送
waz.HelloMethod("Bill" + " " + i);
}
// 取消预定事件: 通过 SOAP 进行
waz.Greeting -= new GreetingEvent(baz.GreetingHandler);
}
}
Makefile
makefile
all: Host.exe Zap.dll Client.exe
Host.exe: Host.cs
csc /r:System.Runtime.Remoting.dll Host.cs
Zap.dll: Zap.cs
csc /t:library -out:Zap.dll Zap.cs
Client.exe: Zap.dll Client.cs
csc /r:System.Runtime.Remoting.dll /r:Zap.dll Client.cs
在一个窗口中启动 host.exe 文件,然后在另一个窗口中启动 client.exe 文件。您将会看到事件被引发回到客户端。
这是诸多 .NET Remoting 应用程序中的一个小例子。.NET Remoting 提供了网络上的完全 CLR 受控代码类型系统,它还是优秀的 SOAP 服务器和客户端,因为它完全符合 SOAP 1.1 规范。
将 SOAP 用作 ATL 开发工具
ATL Server Web Services 为 C++ 开发人员提供了在本机代码中创建和使用 Web Services 的简便方式。ATL Server 是 C++ 开发人员在 Internet 上提供和使用 Web Services 的首选方法,其设计目的是为包含 SOAP 的 Web 应用提供快速、轻便和高度灵活的程序库。
ATL Server 之所以称为 ATL,是因为它体现了同时追求高性能和灵活性的 ATL 目标。例如,您可以很轻易地抛开 ATL Server HTTP 模型,编写您自己的调度程序,同时仍然获得 ATL Server 封送/协议代码的好处。
ATL Server Web Services 使用与 COM 相似的语法说明接口,便于目前的 ATL 开发人员学习。这种与 COM 相似的语法答应开发人员轻而易举地将对象同时以 COM 对象和 Web Service 方式提供。
属性的引入大大简化了代码,使它对于非 ATL 开发人员也很轻易。ATL Server 具有和其他所有 .NET Web Services 进行互操作的能力,这对那些在一个应用程序中使用多种技术的开发人员来说十分方便。
接口:新的 __interface 要害字使开发人员很轻易创建 COM 对象或 Web Services 接口。
[
uuid("D7DAE6FD-AEBB-4579-BD8D-866F74139501"),
object
]
__interface IWeb_Service_ExampleService
{
[id(1)] HRESULT HelloWorld([in] BSTR bstrInput, [out, retval] BSTR *bstrOutput);
};
这是一个运用 ATL Server 定义 Web Service 接口的例子。通过 C++ 属性的运用,嵌入式 IDL 属性和新的 __interface 要害字、ATL Server Web Service 接口看起来和新的属性化的 COM 接口非常相似。这里的 Web Service 接口样例 IWeb_Service_ExampleService 仅实现一个方法 HelloWorld。HelloWorld 用 BSTR 作为输入并返回 BSTR 作为输出。
请求处理程序:请求处理程序是一个 C++ 类,该类通过处理程序映射来提供,并且具有通过替代方法映射来提供的方法。处理程序映射只是文字标签与类名称的映射,而方法映射是类中文字标签与方法的映射。
[
request_handler(name="Default",sdl="GenWeb_Service_ExampleServiceSDL"),
soap_handler(
name="Web_Service_ExampleService",
namespace="urn:Web_Service_ExampleService",
protocol="soap"
)
]
class CWeb_Service_ExampleService:
public IWeb_Service_ExampleService
{
public:
[ soap_method ]
HRESULT HelloWorld(BSTR bstrInput, BSTR *bstrOutput)
{
CComBSTR bstrOut(L"Hello ");
bstrOut += bstrInput;
bstrOut += L"!";
*bstrOutput = bstrOut.Detach();
return S_OK;
}
};
ATL Server 请求处理程序模型与 Web 应用和 Web Services 非常相似。图 1 显示了处理请求的模型:
图 1. ATL Server 请求处理模型
HTTP Request 进入 IIS,将请求(基于 URL 及其扩展)映射到适当的 ISAPI DLL。然后,ISAPI DLL 把在请求中指定的处理程序(即在标签或查询参数中指定的处理程序)映射到适当的 application DLL。Application DLL 再将这个处理程序映射到 C++ 对象。在这个模型(ATL Server 模型)中,Web 应用程序和 Web Service 的唯一差别在于最后一步。使用 Web Services,C++ 对象能够解码/编码 SOAP(当编译器解析 soap_handler 属性时,它会插入执行此操作的代码)。
您可以理解,这个类是从我们的接口继续过来的,并且我们使用 [soap_method] 属性指示将由 HelloWorld 方法来处理 SOAP 请求。实现这种方法和实现任何其他 C++ 方法是一样的。
这个 soap_handler 属性还确保自动生成有效说明服务的 WSDL。Web Service 的用户使用这个对服务的说明(格式为 XML/WSDL),确保他们能够以正确的格式发送/接收正确的数据。
通过 ATL Server 使用 Web Services
通过 ATL Server 使用 Web Services 相对来说是个比较简单的操作。开发人员只需使用 “Add Web Reference” 对话框,将它指向 .disco 文件,然后指向 WSDL,这和使用其他类型的 Web 引用一样。这个对话框在后台运行在 Web Service 的 WSDL 上的 sproxy.exe 实用程序(对于非本机的 .NET Web Services 有另外一个实用程序)。
该操作将创建 Web Service 代理文件,包含要求利用所请求的 Web Service 的全部 C++ 代码。使用 WSDL 中的信息,代理生成器能够判定 Web Service 要接收到的数据以及它要返回给客户端的数据。这就答应代理生成器创建可以和 Web Service“交谈”的头文件。
您只需创建自己的 Web Service 类(如在生成的头文件中查找到的一样)的实例,并且使用合适的方法即可,例如:
CWeb_Service_ExampleServiceService MyService;
CComBSTR bstrOut;
CComBSTR bstrIn(L"World");
MyService.HelloWorld ( bstrIn ,&bstrOut,);
wprintf(bstrOut);
现在,您就已经有一个基本的 ATL Server Web Service 和 ATL Server Web Service Consumer 了。
总结
本文的主要目的是对 .NET 框架和 Visual Studio.NET 中的 SOAP 功能作一个总体的介绍。其次,就如何创建使用 SOAP 的应用程序,给用户一些有益的指导。