在.NET远程处理RemotingConfiguration.RegisterWellKnownServiceType和RemotingServices.Marshal之间有什么区别?

在.NET远程处理RemotingConfiguration.RegisterWellKnownServiceType和RemotingServices.Marshal之间有什么区别?

我想要做的是在Windows服务中创建一个对象,然后将其作为远程处理对象放入,并让Windows服务和客户端都作用于远程处理对象。

我认为下面的代码可以实现这一点。

FooRemoting foo = new FooRemoting(); RemotingConfiguration.RegisterWellKnownServiceType(typeof(FooRemoting), serverName, WellKnownObjectMode.Singleton); RemotingServices.Marshal(foo); 

这就是我发现的。

 RemotingConfiguration.RegisterWellKnownServiceType(typeof(FooRemoting), serverName, WellKnownObjectMode.Singleton); 

RegisterWellKnownServiceType将创建该对象并使其成为使用它的任何客户端的Singleton,但不会创建服务器的引用。 在客户端请求对象之前不会创建该对象,并且该对象用于任何其他客户端。

 RemotingServices.Marshal(foo); 

Marshal将注册一个由服务器创建的对象,在本例中是一个Windows服务。 然后,服务器将引用该对象,并且客户端将使用相同的对象。

我的问题是使用Marshal来注册远程对象。 随着时间的推移,远程处理对象将消失以供客户端使用,即不再在远程处理对象上。 该服务仍将保留其参考。 然后我尝试了RegisterWellKnownServiceType并且客户端不断获得正确的引用,但是我无法让服务获得对同一对象的引用。

在这种情况下,解决方案是覆盖远程处理对象FooRemoting。 如果我覆盖了InitializeLifetimeService并返回null,则客户端永远不会丢失连接,并且服务将保持连接。

 public override object InitializeLifetimeService() { //return base.InitializeLifetimeService(); return null; } 

为了保持服务创建的对象并让客户端使用您必须使用的相同对象

 RemotingServices.Marshal(foo); 

并覆盖InitializeLifetimeService以返回null。

可以通过远程处理来显示具有参数构造函数的MarshalByRefObjects,并且该类的用户可以仅处理其接口。

我创建了一个小概念validation项目。 它有3个项目:服务器,客户端和核心。 服务器和客户端都引用Core但不互相引用。

在核心中,我们定义了一个服务接口:

 namespace Core { public interface ICountingService { int Increment(); } } 

服务器定义具体实现, 客户端没有引用

 namespace Server { public class CountingService : MarshalByRefObject, ICountingService { private static int _value = 0; public CountingService(int startValue) { _value = startValue; } public int Increment() { // not threadsafe! _value++; return _value; } } } 

需要注意的重要事项是它有一个带参数的构造函数,它是一个MarshalByRefObject,它实现了核心项目中的接口。

服务器项目是一个控制台应用程序,它设置远程通道(本例中通过HTTP任意),创建服务,并使用远程处理注册它:

 using System; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; namespace Server { class Program { static void Main(string[] args) { HttpServerChannel serverChannel = new HttpServerChannel(8234); ChannelServices.RegisterChannel(serverChannel, false); // Following line won't work at runtime as there is no parameterless constructor //RemotingConfiguration.RegisterWellKnownServiceType(typeof(CountingService), // "CountingService.rem", WellKnownObjectMode.Singleton); CountingService countingService = new CountingService(5); RemotingServices.Marshal(countingService, "CountingService.rem"); Console.WriteLine("Press enter to exit."); Console.ReadLine(); } } } 

上面的代码已经注册了URL http:// localhost:8234 / CountingService.rem ,它保存了实例化的服务,该服务将从5开始计数。

然后,客户端(也是控制台应用程序)可以使用接口类获取引用

 using System; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; using Core; namespace Client { class Program { static void Main(string[] args) { HttpClientChannel serverChannel = new HttpClientChannel(); ChannelServices.RegisterChannel(serverChannel, false); for (int i = 0; i < 5; i++) { ICountingService countingService = (ICountingService)Activator.GetObject(typeof(ICountingService), "http://localhost:8234/CountingService.rem"); int newValue = countingService.Increment(); Console.WriteLine("Value is " + newValue); } Console.WriteLine("Press enter to exit."); Console.ReadLine(); } } } 

运行服务器和客户端时,它会打印6到10的值。

总结:客户端只知道接口; 实现构造函数可以有参数; 实例化可以由您自己的代码而不是.NET控制。 在处理基于构造函数的dependency injection与远程处理对象时非常有用。

我做了一个像RemotingServices.Marshal这样的实验

Windows操作系统中托管的远程组件。 exe代码是

 Form1_Load(object sender, EventArgs e) { RemotingConfiguration.Configure("path of the config file"); RemoteClass obj = new RemoteClass(); obj.MyVal =100; RemotingServices.Marshal(obj); } public RemoteClass: MarshalByRefObj { static int Counter; public RemoteClass() { Counter++; } int _MyVal =0; public int MyVal { get { return _MyVal; } set { _MyVal = value; } } } 

现在在客户端代码中

 button1_click() { RemoteClass obj = Activator.GetObject(typeof(RemoteClass), "object URI"); if(RemotingServices.IsTransparentProxy(obj)) { MessageBox.Show(obj.Myval.ToString()); } } 

它会将消息弹出为0而不是100.如果在RemoteClass的构造函数中放置一个断点,您将看到构造函数被调用了2次

  1. 在服务本身中创建RemoteClass对象时
  2. 当客户端调用MyVal属性时。

我认为RemotingServices.Marshal与单个实例无关。 即使您只使用RemotingConfiguration.Configure并覆盖InitializeLifetimeService以使其返回null,也足以托管远程组件。