远程方法调用中的参数类型不仅可以是基本的数据类型,还可以是我们自己定义的类。为了进 行远程处理,必须区分下面 3 种类型的类:
● 按值编组的类——这种类通过信道进行序列化。要编组的类必须用 Serializable 特性标记。 这些类的对象没有远程标识,因为完整的对象通过信道编组,而且与客户端序列化的对象 独立于服务器对象(或相反)。按值编组的类也称作未绑定的类,原因是它们没有依赖于应用 程序域的数据。
● 按引用编组的类——这种类有远程标识。对象不是在网络上传递的,而是返回一个代理。 按引用编组的类必须派生自 MarshalByRefObject。MarshalByRefObjects 称为应用程序域绑 定对象。MarshalByRefObject 的一个专业化版本是 ContextBoundObject :抽象类 ContextBoundObject 派生自 MarshalByRefObject。如果类派生自 ContextBoundObject,则当 上下文边界交叉时,甚至在同一应用程序域中也需要代理。这样的对象称为上下文绑定对 象,它们只在创建上下文中有效。
● 不能用于远程通信的类——这种类不能序列化,也不派生自 MarshalByRefObject 的。这些 类型的类不能在远程对象的公共方法中用作参数。它们只能用于创建它们的应用程序域中。 如果类的数据成员只在应用程序域中有效(如Win32 文件句柄)则应该使用这种类。 为了阐明类的编组问题,我们将把远程对象改为向客户端发送一个对象:MySerialized 类将按 值编组。在方法中,消息被写入控制台中,以便验证调用是在客户端上进行还是在服务器上进行。 此外,把 Hello 类扩展为返回 MySerialized 实例。
1. 安全性和序列化的对象
.NETRemoting 和ASP.NET Web 服务的一个重要区别是对象编组的方式。在 ASP.NET Web 服务中,只有公共字段和属性通过网络传输。而.NET Remoting 使用另一种序列化机制来序列化所有数据,包括所有私有数据。恶意客户端可以在序列化和反序列化阶段中破坏应用程序。为了解决这个问题,跨.NET Remoting 边界传递对象时,定义两个自动反序列化级别:低级反序列化和完整反序列化。在默认情况下,使用低级反序列化。在低级反序列化中,不能传递 ObjRef 对象,也不能传递实现ISponsor 接口的对象。为了传递这两类对象,可以把反序列化级别改为完整级别。这可以通过编程方式实现:创建一个格式化程序接收器提供程序,并给它赋予 TypeFilterLevel 属性。对于二进制格式化程序,提供程序类是 BinaryServerFormatterSinkProvider,对于 SOAP 格式化程序,提供程序类是 SoapServerFormatterSinkProvider。
2. 方向特性
远程对象从来都不通过网络传输,而值类型和可序列化的类通过网络传输。有时只需要在一个方向上发送数据。这在数据通过网络传输时尤其重要。例如,如果要把集合中的数据发送给服务器,服务器再对这些数据执行一些计算操作,并给客户端返回一个简单的值,把集合发送回客户端就不是很有效。如果数据应发送给服务器、客户端或双向发送,则可以使用 COM 给参数声明方向特性 [in]、[out]和 [in, out]。在 C#中,有相似的特性:ref 和 out 方法参数。ref 和 out 方法参数可以用于可序列化的值类型和引用类型。使用 ref 参数时,数据可以双向编组;使用 out 时,数据从服务器发送到客户端;不使用参数 ref 和out 时,数据从客户端发送到服务器。