.net通过Remoting实现双向通信

  Remoting是NET平台下比较成熟高效的 分布式技术,我们习惯采用传统的远程调用的方式使用Remoting。在客户端所在的Application Domain,我们通过Proxy(Transparent Proxy)远程地跨Application Domain调用一个方法。当来自Client端的调用请求通过Proxy到达Server端所在的Application Domain后,Remoting Infrastructure在Server 端激活(Activate)相应的远程对象(一个继承子System.MarshalByRefObject类对象)——这里仅仅以服务端激活对象 (Server Activated Object——SAO),然后再Server端执行相应的操作后把Result传递给Proxy,并最终到达Client。这是一种典型的 Request/Response的调用方式。

  之所以一直比较推崇在.NET平台下使用Remoting而非XML Web Service是因为我觉得.NET Remoting是一种比较成熟的分布式技术。它自身提供了XML Web Service很多不具备的特性,其中对双向通信的支持就是一个很好的体现。

  相对于典型的Request/Response 的消息交换模式(Message Exchange Pattern——MEP),双向通信实质上是采用的Duplex的MEP。也就是说,Server端在执行操作的时候,可以回调 (Callback)Client端的操作(这个操作时再Client端的Application Domain中执行的)。

  现在我们来看如何一步一步实现在 Remoting环境下的双向通信。在下面的Sample中,我们的逻辑是:调用一个数学计算的远程调用,除了传递相应的操作数之外,我们还传递一个对 象,这个对象可以在Server端中回调 (Callback) 把运算结果在Client端显示出来。点击这里下载源代码
步骤一、构建整个Solution的整体构架

  • Artech.DuplexRemoting.Contract:Class Library Project,定义远程对象(Remote Object)和Callback对象的Contract(Interface)。实际上,站在Server端的角度上看,Callback的操作是在 Client端的Application Domain中执行的,所以从本质上讲, Callback对象是Server端的远程对象。之所以定义这样一个Contract Project,其目的主要有以下两点:

如果没有把远程对象的Interface, 对已某一个需要调用这个远程对象的Client来说,它必须引用远程对象本身。从安全的角度考虑,Server向Client过多暴露了操作的实现逻辑。 如果我们把远程操作的Contract提取出来,Client只要引用这个Interface就可以了。

一般来说,远程对象的Contract相对时静态的(static),而业务逻辑的实现则是经常 变化的。因为Client只需要了解的是远程对象的Contract,所在无论Server端对远程对象的实现作了多大的变动,对不回对Client产生任何影响。

  • Artech.DuplexRemoting.Remoting:Class Library Project,定义远程对象本身。由于远程对象必须实现上边定义的Contract。所以需要引用Artech.DuplexRemoting.Contract。
  • Artech.DuplexRemoting.Hosting:Console Application Project,以Self-Host的方式Host Remoting。引用Artech.DuplexRemoting.Remoting。
  • Artech.DuplexRemoting.Client:Console Application Project,引用Artech.DuplexRemoting.Contract。
    DuplexRemoting.Client

步骤二、定义Contract

IDuplexCalculator

 
 1: public interface IDuplexCalculator

 2: {

 3:     void Add(double x, double y, ICalculatorCallback callback);

 4: }

ICalculatorCallback

 1: public interface ICalculatorCallback

 2: {

 3:       void ShowResult(double x, double y, double result);

 4: }

步骤三、定义远程对象类型

DuplexCalculatorRemoting

 
 1: public class DuplexCalculatorRemoting : MarshalByRefObject, IDuplexCalculator

 2: {

 3:     public void Add(double x, double y, ICalculatorCallback callback)

 4:     {

 5:         Console.WriteLine("Invoke the method Add({0},{1}).", x, y);

 6:         double result = x + y;

 7:         callback.ShowResult(x, y, result);

 8:     }

 9: }

步骤四、Host远程对象

App.config

 
 1: <configuration>

 2:     <system.runtime.remoting>

 3:         <application name="Calculator">

 4:             <service>            

 5:                 <wellknown mode="SingleCall"

 6:                            type="Artech.DuplexRemoting.Remoting.DuplexCalculatorRemoting,Artech.DuplexRemoting.Remoting"

 7:                            objectUri="DuplexCalculator.soap" />

 8:             </service>

 9:  

 10:             <channels>

 11:                 <channel ref="http" port="8080">

 12:                     <serverProviders>

 13:                         <provider ref="wsdl" />

 14:                         <formatter ref="binary" typeFilterLevel="Full" />

 15:                     </serverProviders>

 16:                     <clientProviders>

 17:                         <formatter ref="binary" />

 18:                     </clientProviders>

 19:                 </channel>

 20:             </channels>

 21:         </application>

 22:     </system.runtime.remoting>

 23: </configuration>

Program.cs

 
 1: class Program

 2: {

 3:     static void Main(string[] args)

 4:     {

 5:         System.Runtime.Remoting.RemotingConfiguration.Configure("Artech.DuplexRemoting.Hosting.exe.config",false);

 6:         Console.WriteLine("Calculator service has begun to listen ");

 7:         Console.Read();

 8:     }

 9: }

这里需要特别注意的有以下两点:

  • 在定义Channel是需要指定一 个双向Channel(Bi-Directional Channel)。系统给我们定义一一系列的System-Defined Channel用于调用远程对象。其中有一些只能提供单向的通信——比如只支持Client到Server的通信,而另一些可以提供双向的通信——比如 TCP Channel 和Http Channel.
  • 在ServerProvider Section,我们必须设置typeFilterLevel为Full。出于安全的考量,Remoting提供了两个反序列化级别(Level)—— Low & Full。Low是默认的,如果把typeFilterLevel设为Low,Remoting之会反序列化Remoting基本功能相关的对象。而设为 Full则意味着Remoting会反序列化所有类型。如果你想知道那些类型是在Low Level下被限制,请参考http://msdn2.microsoft.com/en-us/library/5dxse167.aspx

  之所以要把typeFilterLevel为Full,是因为我们的远程调用里包含一Callback对象,它实际上是一个继承System.MarshalByRefObject类对象(这个的对象将在Artech.DuplexRemoting.Client中定义)。而这个对象是不会再Low Level下被自动反序列化。

 
 1: <channels>

 2:   <channel ref="http" port="8080">

 3:     <serverProviders>

 4:       <provider ref="wsdl" />

 5:       <formatter ref="binary" typeFilterLevel="Full" />

 6:     </serverProviders>

 7:     <clientProviders>

 8:       <formatter ref="binary" />

 9:     </clientProviders>

 10:   </channel>

 11: </channels>


 
 1: public interface IDuplexCalculator

 2: {

 3:      void Add(double x, double y, ICalculatorCallback callback);

 4: }

 

步骤五、定义Callback对象类型和调用远程对象

CalculatorCallbackHandler

 
 1: public class CalculatorCallbackHandler : MarshalByRefObject, ICalculatorCallback

 2: {

 3:     public void ShowResult(double x, double y, double result)

 4:     {

 5:         Console.WriteLine("x + y = {2} where x = {0} and y = {1}", x, y, result);

 6:     }

 7: }

App.config

 
 1: <configuration>

 2: <system.runtime.remoting>

 3:     <application>

 4:         <channels>

 5:             <channel ref="http" port="0">

 6:                 <clientProviders>

 7:                     <formatter ref="binary" />

 8:                 </clientProviders>

 9:                 <serverProviders>

 10:                     <formatter ref="binary" typeFilterLevel="Full" />

 11:                 </serverProviders>

 12:             </channel>

 13:         </channels>        

 14:     </application>

 15: </system.runtime.remoting>

 16: </configuration>


Program.cs

 
 1: class Program

 2: {

 3:     static void Main(string[] args)

 4:     {

 5:         System.Runtime.Remoting.RemotingConfiguration.Configure("Artech.DuplexRemoting.Client.exe.config", false);

 6:  

 7:         InvocateDuplexCalculator("http://localhost:8080/Calculator/DuplexCalculator.soap");

 8:     }

 9:  

 10:     static void InvocateDuplexCalculator(string remoteAddress)

 11:     {

 12:         IDuplexCalculator proxy = (IDuplexCalculator)Activator.GetObject(typeof(IDuplexCalculator), remoteAddress);

 13:         proxy.Add(1, 2, new CalculatorCallbackHandler());

 14:         Console.Read();

 15:     }

 16: }

   这里有两点需特别注意的:

  • 由 于Server端时跨Application Domain远程地调用运行Client Application Domain中的Callback对象(Callback的执行实际是在Client而不在Server),所以Callback对象应该是一个 MarshalByRefObject对象;
  • 上面我们以经提及,对于Server端了来说Callback对象实际上是一个远程对象(在Callback过程中Client端转变成Server端,而Server端转变成Client端)。Server端需要注册一些Channel用于Client访问寄宿在Server端的远程对象,同理,Server需要Callback一个寄宿在Client端Application Domain中的Callback对象,Client端需要注册相应的Channel;
  • 和Server端一样,我们必须设置typeFilterLevel为Full。 

  到现在为止我们已经完成了所有的Program,我们来运行一下,在客户端你将得到如下的输出:

 1: x + y = 3 where x = 1 and y = 2

步骤六、将远程对象Host到IIS中

  我们知道,Remoting有两种Host方式Self Host和IIS Host,上面我们把Remoting Host到一个Console Application中; 现在我们把试着把它Host到IIS中。实际上我们要做的工作很简单。

  • 在IIS Manager中添加一个虚拟目录对应Artech.DuplexRemoting.Remoting文件夹, 假设此虚拟目录的Alias为Artech.DuplexRemoting
  • 在Artech.DuplexRemoting.Remoting根目录下中(也就是在http://localhost/Artech.DuplexRemoting根目录下)添加一个Web.config,并添加类似于Artech.DuplexRemoting.Hosting/App.Config中 的Remoting Configuration。
 
 1: <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

 2:   <system.runtime.remoting>

 3:     <application>

 4:       <service>

 5:         <wellknown mode="SingleCall"

 6:                    type="Artech.DuplexRemoting.Remoting.DuplexCalculatorRemoting,Artech.DuplexRemoting.Remoting"

 7:                    objectUri="DuplexCalculator.soap" />

 8:       </service>

 9:       <channels>

 10:         <channel ref="http">

 11:           <serverProviders>

 12:             <provider ref="wsdl" />

 13:             <formatter ref="binary" typeFilterLevel="Full" />

 14:           </serverProviders>

 15:           <clientProviders>

 16:             <formatter ref="binary" />

 17:           </clientProviders>

 18:         </channel>

 19:       </channels>

 20:     </application>

 21:   </system.runtime.remoting>

 22: </configuration>

这样我们可以不需要Hosting,就可以运行Client了。

作者:Artech
出处:http://artech.cnblogs.com/

加支付宝好友偷能量挖...


评论(0)网络
阅读(219)喜欢(0)Asp.Net/C#/WCF