摘要:本文介绍 Microsoft .NET Romoting 框架的基本原理。除了介绍组成 .NET Romoting 框架的主要组件外,还介绍 .NET Remoting 与分布式对象通信的几种方案。
目录
简介
.NET Remoting 对象
集成 .NET Remoting 对象
.NET Remoting 元数据和配置文件
.NET Remoting 方案
总结
其他资料
简介
Microsoft® .NET Remoting 是一个丰富的、可扩展的框架,它使得处于不同 AppDomain、不同过程和不同机器上的对象可以实现无缝通信。.NET Remoting 提供的编程模型和运行时支持功能强大而又易于使用,能够实现透明的交互操作。本文将浏览 Remoting 体系结构的不同构造块,并研究一些应用 .NET Remoting 的常见方案。.NET Remoting 对象可以作为一种 Web 服务使用(请参阅 MSDN Magazine 文章“可编程 Web:Web 服务为 Microsoft .NET 框架提供构造块(英文)”,允许从任何能够执行 SOAP 调用的客户端访问 .NET Remoting 对象。有关 .NET Remoting 的概述信息,请先阅读文章“Microsoft .NET Remoting:技术概述(英文)”。
.NET Remoting 对象
有三类对象可以被配置为 .NET 远程对象。您可以根据应用程序的需要选择对象类型。本节将详细介绍这些对象。
“单一调用对象”仅为一个请求提供服务。在需要对象完成的工作量有限,并且不必存储状态信息的情况下,单一调用对象非常有用。单一调用对象可以被配置为负载平衡模式。在方法调用之间,单一调用对象不能保留状态信息。
“单一元素对象”可以为多个客户端提供服务,因此可以通过保存客户端调用的状态信息来实现数据共享。当客户端需要明确地共享数据,并且不能忽略创建和维护对象的开销时,这种对象非常有用。
“客户端激活的对象 (CAO)”是服务器端的对象,收到来自客户端的请求时会激活这些对象。这种激活服务器对象的方法与传统的 COM coclass 激活方法很相似。当客户端使用“new”操作符请求服务器对象时,将向远程应用程序发送一个激活请求消息。随后,服务器将创建被请求类的实例,并向调用它的客户端应用程序返回 ObjRef。客户端将使用此 ObjRef 创建代理。客户端的方法调用将在代理上执行。客户端激活的对象可以为其特定的客户端(不能跨越不同的客户端对象)保存方法调用之间的状态信息。每次“new”调用都会返回服务器类型的独立实例的代理。
使用 .NET Remoting 传递对象
在 .NET Remoting 中,可以通过以下方式在应用程序之间传递对象:
作为方法调用的参数
示例:public int myRemoteMethod (MyRemoteObject myObj)
方法调用的返回值
示例:public MyRemoteObject myRemoteMethod(String myString)
访问 .NET 组件的属性或字段得到的值
示例:myObj.myNestedObject
对于 Marshal By Value (MBV) 的对象,当它在应用程序之间传递时,将创建一个完整的副本。
对于 Marshal By Reference (MBR) 的对象,当它在应用程序之间传递时,将创建该对象的引用。当对象引用 (ObjRef) 到达远程应用程序后,将转变成“代理”返回原始对象。
简单 .NET Remoting 服务器对象的代码示例
using System;
using System.Runtime.Remoting;
namespace myRemoteService
{
// 有名的 Web 服务对象
public class myRemoteObject : MarshalByRefObject
{
// myRemoteMethod 方法
public String myRemoteMethod(String s)
{
return "Hello World";
}
}
}
访问此对象的客户端代码示例
using System;
using System.Runtime.Remoting;
using myRemoteService;
public class Client
{
public static int Main(string[] args)
{
ChannelServices.RegisterChannel(new HTTPChannel(7055));
// 创建 myRemoteObject 类的实例
myRemoteObject myObj = ( myRemoteObject)Activator.GetObject(typeof(myRemoteObject),
"http://myHost:7021/host/myRemoteObject.soap");
myObj. myRemoteMethod ("Hello World");
return 0;
}
}
租用生存期
对于那些具有在应用程序之外传送的对象引用的对象,将创建一个租用。租用具有一个租用时间。如果租用时间为 0,则租用过期,对象将断开与 .NET Romoting 框架的连接。一旦 AppDomain 内部所有的对象引用都被释放,则下一个 GC 发生时对象将被回收。租用控制了对象的生存期。
对象有默认的租用阶段。当客户端要在同一服务器对象中维护状态信息时,可以通过许多方法扩展租用阶段,使对象继续生存。
可以将服务器对象的租用时间设置为无限,这样 Remoting 在垃圾回收周期中就不会回收此对象。
客户端可以调用 RemotingServices.GetLifetimeService 方法,以从 AppDomain 的租用管理器获取服务器对象的租用时间。然后,客户端便可以通过 Lease 对象来调用 Lease.Renew 方法,以延长租用时间。
客户端可用 AppDomain 的租用管理器为特定的租用注册负责人。当远程对象租用过期时,租用管理器将通知负责人提出更新租用的申请。
如果设置了 ILease::RenewOnCallTime 属性,则每次调用远程对象时,都会用 RenewOnCallTime 属性指定的时间更新租用时间。
单一调用/单一元素对象 客户端激活的对象
客户端激活代码(客户端所需的代码)
有关详细信息,请参阅配置文件的相关小节
a) Activator.GetObject()
b) new() 及 CFG 文件
客户的 CFG 文件引用下列 URL:
Foo= http://localhost:80/ObjectZone/Foo.soap
a) Activator.CreateInstance()
b) new() 及 CFG 文件
客户的 CFG 文件引用服务器数据库以及服务器应用程序的 URL,并提供对象 URI。客户端内置了对这些数据库的引用:
Assembly#MyObjectLibrary#ObjectZone#
MyObjectLibrary.Baz
RemoteApplication#ObjectZone#
HTTP://localhost:80/ObjectZone
服务器对象的激活 在首次调用方法之前,不会在网络上发送激活消息 当客户端创建对象,并且在客户端生成代理之后,激活消息将发送至服务器。支持带参数的构造函数。
服务器对象的生存期 生存期由服务器上的配置设定,可以为 SingleCall 或 Singleton 生存期在下列两个事件之一发生时结束:
a) 租用过期
b) 客户释放在服务器对象上的引用时
服务器端注册 a) 使用配置文件来指定类型(SingleCall 或 Singleton)
b) 使用 RegisterWellKnownType() API 注册类型
使用配置文件来导出客户端激活的对象
有关详细信息,请参阅配置文件的相关小节
模型的优点 a) 可以利用服务器组件的基类或接口定义公共语言运行时元数据来编译客户端
b) 在服务器端执行有限操作的情况下很有用处
c) 单一调用对象不保存状态信息,所以易于在负载平衡系统中进行配置
d) 单一元素对象可以在多个客户对象之间维护状态信息
a) 服务器对象的调用与传统的 COM“coclass”类似
b) 客户端可以更加灵活地管理服务器对象的生存期
c) 客户端能够向被创建的对象传递构造函数参数
d) 服务器对象可以为其特定客户端在多次方法调用之间保留状态信息
集成 .NET Remoting 对象
.NET Remoting 对象可以集成在:
托管可执行项:.NET Remoting 对象可以集成在任何常规的 .NET EXE 或托管服务中。
IIS:Remoting 对象可以集成在 Internet Information Server (IIS) 中。默认情况下,集成在 IIS 中的 Remoting 对象通过 HTTP 通道接收消息。要在 IIS 中集成 Remoting 对象,必须创建一个虚拟根目录,并将 remoting.cfg 文件复制到其中。包含远程对象的可执行文件或 DLL 应放置在 IIS 根目录下的 bin 目录中。需要注意的是,IIS 根目录的名称应该与配置文件中指定的应用程序名称相同。当应用程序接收到第一个消息时,远程配置文件将自动加载。使用这种方法,可以将 .NET Remoting 对象作为 Web 服务提供。
Remoting.cfg 文件示例:
Name#HelloService
WellKnownObject#HelloService.Hello#HelloService#HelloService/
Hello.soap#SingleCall
其格式为:
Name#[Name of the Application]
WellKnownObject#[FullTypeName]#[AssemblyName]#[ObjectURI]#[ObjectMode]
.NET 组件服务:.NET Remoting 对象可以集成在 .NET 组件服务基础结构中,从而利用各种 COM+ 服务,例如:事务、JIT、对象池等。
有关详细信息,请参阅 Microsoft .NET 框架组件服务,第 1 部分(英文)。
通道服务 (System.Runtime.Remoting.Channels)
.NET 应用程序和 AppDomains 之间使用消息进行通信。.NET “通道服务”为这一通信过程提供了底层传输机制。
.NET 框架提供了 HTTP、TCP 和 SMTP 通道,但是第三方也可以编写并使用自己的通道。默认情况下,HTTP 和 SMTP 通道使用 SOAP 进行通信,而 TCP 通道使用二进制有效负载。
通过使用可以编写到集成混合应用程序中的自定义通道,可以插入通道服务(使用 IChannel)。
加载通道服务的代码示例
public class myRemotingObj
{
HTTPChannel httpChannel;
TCPChannel tcpChannel;
public void myRemotingMethod()
{
httpChannel = new HTTPChannel();
tcpChannel = new TCPChannel();
ChannelServices.RegisterChannel(httpChannel);// 注册 HTTP 通道
ChannelServices.RegisterChannel(tcpChannel);// 注册 TCP 通道
}
}
序列化格式化程序 (System.Runtime.Serialization.Formatters)
.NET 序列化格式化程序对 .NET 应用程序和 AppDomains 之间的消息进行编码和解码。在 .NET 运行时中有两个本地格式化程序,分别为 Binary (System.Runtime.Serialization.Formatters.Binary) 和 SOAP (System.Runtime.Serialization.Formatters.Soap)。
序列化格式化程序是可插入的,方法是实例化 IRemotingFormatter 接口,并将其插入到上文介绍的通道中。这样,您可以灵活地选择通道和格式化程序的组合方式,采用最适合应用程序的方案。本文后面的小节将讨论这一问题。
例如:您可以采用 HTTP 通道和 Binary 格式化程序(串行化二进制数据),也可以采用 TCP 通道和 SOAP 格式化程序。
Remoting 上下文
“上下文”是一个包含共享公共运行时属性的对象的范围。一些有关上下文属性的例子是与同步和线程紧密相关的。当 .NET 对象被激活时,运行时将检查当前的上下文是否一致,如果不一致,将创建新的上下文。多个对象可以同时在一个上下文中运行,并且一个 AppDomain 中可以有多个上下文。
一个上下文中的对象调用另一个上下文中的对象时,调用将通过上下文代理来执行,并且会受组合上下文属性的强制策略影响。新对象的上下文通常是基于类的元数据属性选择的。
可以与上下文绑定的类称作上下文绑定类。上下文绑定类可以具有称作“上下文属性”的专用自定义属性。上下文属性是完全可扩展的,您可以创建这些属性并将它们附加到自己的类中。与上下文绑定的对象是从 System.ContextBoundObject 导出的。
.NET Remoting 元数据和配置文件
.NET 框架使用元数据和程序集来存储有关组件的信息,使得多语言编程技术成为可能。.NET Remoting 使用元数据动态地创建代理对象。在客户端创建的代理对象的成员与原始类相同。但是,代理对象的实现仅仅将所有的请求通过 .NET Remoting 运行时转发给原始对象。序列化格式化程序使用元数据将方法调用转换为有效负载数据流,并将有效负载数据流转换回方法调用。
客户端可以通过以下方法获取访问远程对象所需的元数据信息:
服务器对象的“.NET 程序集”- 服务器对象可以创建元数据程序集,并将其分发给客户端。在编译客户端对象时,客户端对象可以引用这些程序集。在客户端和服务器都是托管组件的封闭环境中,这种方法非常有用。
远程对象可以提供 WSDL(请参阅 Web 服务说明语言 [WSDL] 1.0 [英文])文件,用于说明对象及其方法。所有可以根据 WSDL 文件读取和生成 SOAP 请求的客户端都可以调用此对象,或使用 SOAP 与之通信。使用与 .NET SDK 一同分发的 SOAPSUDS.EXE 工具,.NET Remoting 服务器对象可以生成具有元数据功能的 WSDL 文件。当组织希望提供所有客户都能访问和使用的公共服务时,这种方法非常有用。
.NET 客户可以使用 SOAPSUDS 工具从服务器上下载 XML 架构(在服务器上生成),生成仅包含元数据(没有代码)的源文件或程序集。您可以根据需要将源文件编译到客户端应用程序中。如果多层应用程序中某一层的对象需要访问其他层的远程对象,则经常使用此方法。
“配置文件”(.CFG 文件)用于指定特定对象的各种 Remoting 特有信息。通常情况下,每个 AppDomain 有自己的 CFG 文件。使用 CFG 文件有助于实现位置的透明性。CFG 文件中的详细信息也可以通过编程来指定。使用 CFG 文件的主要好处在于,它将与客户端代码无关的配置信息分离出来,这样,在日后更改时仅需要修改 CFG 文件,而不用编辑和重新编译源代码。.NET Remoting 的客户端和服务器对象都使用配置文件。
典型的 CFG 文件包含以下信息及其他信息:
集成应用程序信息
对象名称
对象的 URI
注册的通道(可以同时注册多个通道)
服务器对象的租用时间信息
示例配置文件(请注意,在后续版本中可能会采用 XML 格式):
Name#MyRemoteApp
myRemoteObj = HTTP://myCompany:80/MyRemoteApp/myRemoteObj.soap
Channel#System.Runtime.Remoting#System.Runtime.Remoting.Channels.TCP.TCPChannel
Channel#System.Runtime.Remoting#System.Runtime.Remoting.Channels.HTTP.HTTPChannel
.NET Remoting 方案
了解 .NET Remoting 如何工作之后,让我们来考察不同的方案,分析如何在不同的方案中充分发挥 .NET Remoting 的性能。下表列出了可能的客户端/服务器组合,以及默认情况下采用的底层协议和有效负载。请注意,.NET Remoting 框架是可扩展的,您可以编写自己的通信通道和序列化格式化程序。
客户端 服务器 有效负载 协议
.NET 组件 .NET 组件 SOAP/XML http
.NET 组件 .NET 组件 二进制 TCP
托管/非托管 .NET Web 服务 SOAP/XML http
.NET 组件 非托管的传统 COM 组件 NDR(网络数据表示形式) DCOM
非托管的传统 COM 组件 .NET 组件 NDR DCOM
任何客户端 <-> .NET,使用 HTTP-SOAP
Web 服务是可以通过 URL 寻址的资源,并通过编程向需要使用这些资源的客户端返回信息。客户端使用 Web 服务时不必考虑其实现细节。Web 服务使用称为“合约”的严格定义的接口,此接口采用 Web 服务描述语言 (WSDL) 文件定义。有关 WSDL 的详细信息,请参阅 Web 服务描述语言 (WSDL) 1.0(英文)。
可以将 .NET Remoting 对象集成在 IIS 中,使它们作为 Web 服务使用。任何可以使用 WSDL 文件的客户端,都可以按照 WSDL 文件中指定的约定对远程对象执行 SOAP 调用。IIS 使用 ISAPI 扩展将这些请求路由到相应的对象。这样,远程对象就可以作为 Web 服务对象来使用,从而充分发挥 .NET 框架基础结构的作用。如果您希望不同平台/环境的程序均能够访问对象,则可以采用这种配置。有关 Web 服务的详细信息,请参阅可编程 Web:Web 服务为 Microsoft .NET 框架提供构造块(英文)。这种配置方法便于客户端通过防火墙访问您的 .NET 对象。
图 1:通过 HTTP-SOAP 调用 Remoting 对象的 Web 服务的客户端示例
.NET <-> .NET,使用 SOAP-HTTP 通道
默认情况下 HTTP 通道使用 SOAP 格式化程序,因此,如果客户端需要通过 Internet 访问对象,则可以使用 HTTP 通道。由于这种方法使用 HTTP,所以允许客户端通过防火墙远程访问 .NET 对象。只需按前一节中介绍的方法将这些对象集成在 IIS 中,即可将其配置为 Web 服务对象。随后,客户端就可以读取这些对象的 WSDL 文件,以便使用 SOAP 与 Remoting 对象通信。
.NET <-> .NET,使用 TCP 通道
默认情况下,TCP 通道使用二进制格式化程序。此格式化程序以二进制格式进行数据的序列化,并使用原始套接字在网络中传送数据。如果对象部署在受防火墙保护的封闭环境中,则此方法是理想的选择。该方法使用套接字在对象之间传递二进制数据,因此性能更好。由于它使用 TCP 通道来提供对象,因此具有在封闭环境中开销较小的优点。由于防火墙和配置问题,此方法不能在 Internet 上使用。
图 2:通过 TCP 通道在多个机器之间调用 Remoting 对象的客户端示例
.NET <-> 非托管的 COM 组件 <-> .NET
您可以通过 COM Interop Service 调用非托管的传统 COM 组件。当 .NET Remoting 客户端对象创建 COM 对象的实例时,对象通过运行时可调用包装程序 (RCW) 来提供,而 RCW 则作为真实非托管对象的代理。这些包装程序看起来和 .NET 客户端的任何其他托管类一样,但实际上,它们仅仅是托管 (.NET) 和非托管 (COM) 代码之间的封送调用。
类似地,您可以将 .NET Remoting 服务器对象提供给传统 COM 客户端。当 COM 客户端创建 .NET 对象的实例时,对象通过 COM 可调用包装程序 (CCW) 来提供,而 RCW 则作为真实非托管对象的代理。
这两种方案都使用 DCOM 通信。如果环境中既有传统的 COM,又有 .NET 组件,那么这种互操作性将为您提供便利。有关此主题的详细信息,请参阅 COM 互操作性规范(英文)。
总结
Microsoft .NET 框架提供了强大、可扩展、不依赖于语言的框架,用于开发可靠、可伸缩的分布式系统。.NET Romoting 框架提供了根据系统需求进行远程交互的强大手段。.NET Remoting 实现了与 Web 服务的无缝集成,并有一些方法可以提供 .NET 对象以进行多平台访问的方法
……