正在 .NET 中构建一个需要使用分布式对象的应用程序,并且分布式对象的生存期由客户端控制。您的要求包括能够按值或按引用来传递对象,无论这些对象驻留在同一台计算 机上,还是驻留在同一个局域网 (LAN) 中的不同计算机上,或者是驻留在广域网 (WAN) 中的不同计算机上。

实现策略

这 种模式为在 .NET Remoting 中实现客户端激活对象提供了两种实现方式。客户端激活对象 (CAO) 和服务器激活对象 (SAO) 之间的主要区别在于,是什么控制着远程对象的生存期。在使用 CAO 的情况下,客户端控制着生存期;而在使用 SAO 的情况下,服务器控制着生存期。这里采用的示例在功能上类似于使用服务器激活对象在 .NET 中实现 Broker 中采用的示例。正如 .NET 文档和示例中描述的那样,第一种实现使用了客户端激活。这种实现展示了客户端激活对象的能力;不过,它们也有一些缺点。第二种实现(称为混合法)则解决了这些问题。

客户端激活对象实现

RecordingsManager 类有一个名为 GetRecordings 的方法,它从数据库中检索一列记录,然后在 DataSet 中返回结果。该类扩展了 MarshalByRefObject 类,以确保在远程处理情况下使用 Broker 对象,而不是将对象从服务器复制到客户端。这里描述的功能与"使用服务器激活对象在 .NET 中实现 Broker"中所描述的示例的功能完全相同。

RecordingsManager.cs

以下示例显示了 RecordingsManager类,该类负责从数据库中检索 DataSet:

using System;

using System.Data;

using System.Data.SqlClient;

public class RecordingsManager : MarshalByRefObject

{

public DataSet GetRecordings()

{

String selectCmd = "select * from Recording";

SqlConnection myConnection = new SqlConnection(

"server=(local);database=recordings;Trusted_Connection=yes");

SqlDataAdapter myCommand =

new SqlDataAdapter(selectCmd, myConnection);

DataSet ds = new DataSet();

myCommand.Fill(ds, "Recording");

return ds;

}

}

HttpServer.cs

以下代码将服务器配置为允许使用 new 运算符创建客户端激活对象。该代码利用应用程序名以及要创建的对象的类型来配置服务器,而不是实际地注册一个示例(如 SAO 示例所示)。远程对象的 URL 是 http://localhost:8100/RecordingsServer。SAO 由本地主机上的框架在后台自动创建。该 SAO 负责接受来自客户端的请求,并在客户端请求对象时创建这些对象。

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class HttpServer

{

static void Main(string[] args)

{

HttpChannel channel = new HttpChannel(8100);

ChannelServices.RegisterChannel(channel);

RemotingConfiguration.ApplicationName = "RecordingsServer";

RemotingConfiguration.RegisterActivatedServiceType(

typeof(RecordingsManager));

Console.WriteLine("Recordings Server Started");

Console.ReadLine();

}

}

HttpClient.cs

为了能够使用 new 运算符,并且使远程处理框架创建一个远程对象(与本地对象相反),必须首先将远程对象的类型与服务器设置 ApplicationName 属性时所指定的 URL 相关联。该示例将 ApplicationName 定义为 RecordingsServer,并且使用本地主机上的端口 8100。

using System;

using System.Data;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

class HttpClient

{

[STAThread]

static void Main(string[] args)

{

HttpChannel channel = new HttpChannel();

ChannelServices.RegisterChannel(channel);

RemotingConfiguration.RegisterActivatedClientType(

typeof(RecordingsManager),

"http://localhost:8100/RecordingsServer");

RecordingsManager mgr = new RecordingsManager();

Console.WriteLine("Client.main(): Reference acquired");

DataSet ds = mgr.GetRecordings();

Console.WriteLine("Recordings Count: {0}",

ds.Tables["recording"].Rows.Count);

}

}

注册远程对象会将该对象的类型与 URL 相关联。之后,通过调用 new 在服务器上创建一个远程对象。该对象看起来与代码中的任何其他对象一样。

这种实现允许在客户端的控制下直接创建远程对象。另外,这种实现还表明,在配置客户端之后,创建对象的操作与使用 new 运算符在本地创建对象完全相同。不过,它有一个较大的缺点。这就是,您不能使用 SAO 模式中所描述的共享接口方式。这意味着,必须将编译好的对象传递给客户端。有关使用 SoapSuds 的其他替代方式,请参阅 Advanced .NET Remoting [Ingo02]。

注意:传送经过编译的服务器对象违反了分布式对象的一般原则。另外,由于部署和版本控制问题,也不应该这样做。

为了解决一部分这样的问题,下面的实现描述了混合法如何使用 SAO 创建对象。这种方式使客户端能够控制对象的生存期,而不必将服务器代码传送到客户端。

混合法

混合法需要使用 RecordingsFactory SAO,它提供了创建 RecordingsManager CAO 的方法。(如果您不熟悉 SAO 示例,请参阅"使用服务器激活对象通过 .NET Remoting 实现 Broker"。)下面的类图表描述了总体解决方案。

1: 混合法的结构

这种实现使用了 SAO 示例中所描述的共享接口法。IRecordingsManagerIRecordingsFactory 这两个接口位于客户端和服务器所共享的程序集中。IRecordingsFactory 有一个 Create 方法,它可以返回一个对象来实现 IRecordingsManager 接口。这是 AbstractFactory [Gamma95] 模式的一个例子。因为客户端只依靠接口,所以无需传送服务器代码。当客户端需要 IRecordingsManager 对象时,它调用 IRecordingsFactory 实例的 Create 方法。这样,客户端就可以控制 IRecordingsManager 对象的生存期,而无需实现该对象。共享程序集中的两个接口是:

IRecordingsManager.cs

以下示例显示了 IRecordingsManager 接口:

using System;

using System.Data;

public interface IRecordingsManager

{

DataSet GetRecordings();

}

IRecordingsFactory.cs

以下示例显示了 IRecordingsFactory 接口:

using System;

public interface IRecordingsFactory

{

IRecordingsManager Create();

}

这些对象的服务器实现(RecordingsFactoryRecordingsManager)非常简单,并且包含在它们自己的、名为 Server 的程序集中。

RecordingsFactory.cs

该类扩展了 MarshalByRefObject,并实现了 IRecordingsFactory 接口:

using System;

public class RecordingsFactory : MarshalByRefObject, IRecordingsFactory

{

public IRecordingsManager Create()

{

return new RecordingsManager();

}

}

RecordingsFactory 对象是服务器激活对象。该实现只是对 RecordingsManager 类型调用 new。该 RecordingsManager 对象是在服务器上创建的,并且,不是作为 RecordingsManager 对象、而是作为 IRecordingsManager 接口返回的。利用这种机制,客户端就可以依赖于接口而不是实现。

RecordingsManager.cs

RecordingsManager 类所需要的唯一更改是,它现在实现的是 IRecordingsManager 接口。

using System;

using System.Reflection;

using System.Data;

using System.Data.SqlClient;

public class RecordingsManager : MarshalByRefObject, IRecordingsManager

{

public DataSet GetRecordings()

{

Console.WriteLine("Assembly: {0} - filling a request",

Assembly.GetEntryAssembly().GetName().Name);

String selectCmd = "select * from Recording";

SqlConnection myConnection = new SqlConnection(

"server=(local);database=recordings;Trusted_Connection=yes");

SqlDataAdapter myCommand =

new SqlDataAdapter(selectCmd, myConnection);

DataSet ds = new DataSet();

myCommand.Fill(ds, "Recording");

return ds;

}

}

HttpServer.cs

混合法中的服务器初始化代码用于为服务器激活的 RecordingsFactory 对象配置远程处理框架。激活方式与所使用的通道和协议无关,因此与以前一样(端口 8100 上的 HTTP 协议)。

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class HttpServer

{

static void Main(string[] args)

{

HttpChannel channel = new HttpChannel(8100);

ChannelServices.RegisterChannel(channel);

RemotingConfiguration.RegisterWellKnownServiceType(

typeof(RecordingsFactory),

"RecordingsFactory.soap",

WellKnownObjectMode.Singleton);

Console.ReadLine();

}

}

在该代码中,RecordingsFactory 类型与 URL http://localhost:8100/RecordingsFactory.soap 相关联。

HttpClient.cs

客户端代码显示了这种方式的混合性质。首先使用 Activator.GetObject 方法从服务器检索 IRecordingsFactory 对象。然后,使用这个服务器激活对象来调用 Create 方法,以便实例化一个 IRecordingsManager 对象。这个新实例化的对象是在服务器上创建的,但它是一个远程对象。

using System;

using System.Data;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

public class HttpClient

{

[STAThread]

static void Main(string[] args)

{

HttpChannel channel = new HttpChannel();

ChannelServices.RegisterChannel(channel);

IRecordingsFactory factory = (IRecordingsFactory)

Activator.GetObject(typeof(IRecordingsFactory),

"http://localhost:8100/RecordingsFactory.soap");

Console.WriteLine("Client.main(): Factory acquired");

IRecordingsManager mgr = factory.Create();

DataSet ds = mgr.GetRecordings();

Console.WriteLine("Recordings Count: {0}",

ds.Tables["recording"].Rows.Count);

}

}

使用客户端激活对象通过 .NET Remoting 来实现 Broker 具有以下优缺点:

优点

  • 分布式对象模型。 .NET remoting 为全功能的分布式对象模型提供了运行在客户端和服务器上的完整公共语言运行库语义。客户端和服务器之间所传递的数据的保真度不会受任何影响。该示例显示了如何在客户端和服务器之间传递复杂类型 System.Data.DataSet。如果连接的两端没有公共语言运行库,就不可能实现这样的传递。
  • 构造参数。客户端激活实现和混合实现中的对象都考虑到了在创建对象时传递构造函数的参数。

缺点

  • 远程对象。 您必须记住,这些对象是远程对象。即使它们看上去像是本地对象,但从服务器来回封送数据仍然需要开销。记住,远程调用比公共语言运行库中的本地调用至少慢 1000 倍。因此,您应当只在需要时才进行这样的调用。由于需要最大限度地减少往返操作,这可能导致您在处理接口时不会使用最细的粒度。
  • 无共享程序集。在 CAO 方式中,不能使用共享程序集方式来处理接口。相反,必须将实现传送到客户端,或使用 SoapSuds 提取元数据。
  • 部署的复杂性。使用混合法中所描述的服务器激活对象时,在客户端请求对象之前必须已经注册了该对象。这会使部署变得更加复杂。
  • 有限的互操作性。 您可以使用 .NET Remoting 来构建 Web Service。不过,必须将端点减少到最简单的数据类型。例如,如果希望与其他 Web Service 工具包实现互操作,必须将参数限制为内置的简单类型和您自己的数据类型(不使用 .NET Framework 类型,例如 DataSet),并且使用服务器激活对象。
  • 更加复杂。与 Web Service 相比,.NET Remoting 更难学习、实现和调试。

安全考虑事项

要 使用 Microsoft Internet 信息服务 (IIS) 所提供的安全功能(例如,标准 HTTP 身份验证方案,包括基本验证、摘要式验证、数字证书,甚至 Microsoft .NET Passport),您必须使用一个基于 HTTP 的应用程序,而且该应用程序应当驻留在具有 ASP.NET 环境的 IIS 中。如果要使用其他任何传输协议,或使用 IIS 之外的 HttpChannel,都需要您提供安全机制。

操作考虑事项

以 下是 MSDN文章"Performance Comparison: .NET Remoting vs. ASP.NET Web Services"(.NET Remoting 与. ASP.NET Web Service 的性能比较)[Dhawan02] 中的性能比较的概述。该文的结论是,通过使用 TCP 通道和二进制序列化以及 Windows 服务主机,您可以实现最高性能。这种配置通过原始 TCP 套接字传输二进制数据,这比 HTTP 更有效。与 HttpChannel(它使用驻留在具有 ASP.NET 的 IIS 中的 SOAP 序列化)这种最慢的方法相比,其性能快 60%。

驻留在 IIS 中会导致性能下降,因为它涉及从 IIS (Inetinfo.exe) 到 Aspnet_wp.exe 的额外进程跳跃。不过,如果选择在没有 IIS 和 ASP.NET 的情况下驻留您的通道,则需要提供您自己的身份验证、授权和隐私机制。

第5章分布式系统模式 使用客户端激活对象通过 .NET Remoting 实现 Broker的更多相关文章

  1. 第5章分布式系统模式 使用服务器激活对象通过 .NET Remoting 实现 Broker

    正在使用 Microsoft? .NET Framework 构建一个需要使用分布式对象的应用程序.您的要求包括能够按值或按引用来传递对象,无论这些对象驻留在同一台计算机上,还是驻留在同一个局域网 ( ...

  2. 第5章分布式系统模式 Broker(代理程序)

    许多复杂的软件系统运行在多个处理器或分布式计算机上.将软件分布在多台计算机上的原因有多种,例如: 分布式系统可以利用多个 CPU 或一群低成本计算机的计算能力. 某个软件可能仅在特定计算机上可用. 出 ...

  3. 第5章分布式系统模式 在 .NET 中使用 DataSet 实现 Data Transfer Object

    要在 .NET Framework 中实现分布式应用程序.客户端应用程序需要显示一个窗体,该窗体要求对 ASP.NET Web Service 进行多个调用以满足单个用户请求.基于性能方面的考虑,我们 ...

  4. 第5章分布式系统模式 Data Transfer Object(数据传输对象)

    正在设计一个分布式应用程序,为了满足单个客户端请求,您发现自己对一个远程接口发出了多个调用,而这些调用所增加的响应时间超出了可接受的程度. 影响因素 在与远程对象通信时,请考虑下列需要权衡的因素: 远 ...

  5. 第5章分布式系统模式 Singleton

    上下文 在某些情况下,特定类型的数据需要提供给应用程序中的其他所有对象使用.在大多数情况下,这种类型的数据在系统中还是唯一的.例如,用户界面只能有一个所有应用程序必须访问的鼠标指针.同样,企业解决方案 ...

  6. 使用Micrisoft.net设计方案 第二章组织模式

    第二章组织模式 模式不仅依赖于它所包含的更小模式,同时也依赖包含它的更大的模式.它是描述复杂软件的系统方法. 本章的目标是让我们了解以下问题: 1.如何标识模式与模式的关系 2.如何把模式组织成模式集 ...

  7. 第14章 命令模式(Command Pattern)

    原文 第14章 命令模式(Command Pattern) 命令模式(Command Pattern) 概述   在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”.但在某些场合,比如 ...

  8. 第12章 代理模式(Proxy Pattern)

    原文   第12章 代理模式(Proxy Pattern) 代理模式 概述: 在软件系统中,有些对象有时候由于跨越网络或者其他的障碍,而不能够或者不想直接访问另一个对象,如果直接访问会给系统带来不必要 ...

  9. 第10章 外观模式(Façade Pattern)

    原文   第10章 外观模式(Façade Pattern) 概述:   在软件开发系统中,客户程序经常会与复杂系统的内部子系统之间产生耦合,而导致客户程序随着子系统的变化而变化.那么如何简化客户程序 ...

随机推荐

  1. [Advanced Algorithm] - Validate US Telephone Numbers

    题目 如果传入字符串是一个有效的美国电话号码,则返回 true. 用户可以在表单中填入一个任意有效美国电话号码. 下面是一些有效号码的例子(还有下面测试时用到的一些变体写法): 555-555-555 ...

  2. 【sqli-labs】 less29 GET- Error based -Impidence mismatch -Having a WAF in front of web application (GET型基于错误的带有WAF注入)

    这关有点意思,有一点需要事先注意,这关玩的是login.php而不是默认的index.php 再注入之前需要先了解一下HPP(HTTP Parameter Pollution),详情参照这篇 http ...

  3. HDU_2149_基础博弈sg函数

    Public Sale Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  4. excel 处理方法

    //.方法一:采用OleDB读取EXCEL文件: //打开excel 返回指定表中的所有数据 public DataSet ExcelToDS(string Path) { string strCon ...

  5. H5-data属性的一个问题

    关于前端存数据的问题,前面写过一个博客:前端页面存取数据 看个例子: <!DOCTYPE html> <html lang="en"> <head&g ...

  6. JAVA中实现根据文件路径下载文件

    import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream; ...

  7. NFS实时备份

    方法一(inotify+rsync): 1.安装inotify-tools(客户端)[监听工具],实现数据属实备份检查目录是否有如下文档,没有表示操作系统不支持 ls -l /proc/sys/fs/ ...

  8. 2018ICPC南京

    可能上一次秦皇岛拿了银,有了偶像包袱? 打的时候感觉状态不是很好. 第一题,让你每次将连续一段区间的石头都拿掉.. 然后让你做个博弈. 橘子一顿分析,认为k+1的倍数都是输. 这时,我们以及默认i+1 ...

  9. 转载 - C++ bitset类使用与简介

    出处:http://blog.163.com/lixiangqiu_9202/blog/static/53575037201251121331412/ C++ bitset类的使用与简介   有些程序 ...

  10. asp.net--owin的知识点

    一篇很好的介绍owin的文章 http://kb.cnblogs.com/page/509236/ Owin在webconfig中定义启动配置类IdentityConfig的方法(代码来自极客学院的教 ...