在.NET远程处理RemotingConfiguration.RegisterWellKnownServiceType和RemotingServices.Marshal之间有什么区别?
我想要做的是在Windows服务中创建一个对象,然后将其作为远程处理对象放入,并使Windows服务和客户端都作用于远程处理对象.
我认为下面的代码可以实现这一点.
FooRemoting foo = new FooRemoting();
RemotingConfiguration.RegisterWellKnownServiceType(typeof(FooRemoting), serverName, WellKnownObjectMode.Singleton);
RemotingServices.Marshal(foo);
Run Code Online (Sandbox Code Playgroud)
Dav*_*rab 20
这是我发现的.
RemotingConfiguration.RegisterWellKnownServiceType(typeof(FooRemoting),
serverName, WellKnownObjectMode.Singleton);
Run Code Online (Sandbox Code Playgroud)
RegisterWellKnownServiceType将创建该对象并使其成为使用它的任何客户端的Singleton,但不会创建服务器的引用.在客户端请求该对象之前不会创建该对象,并且该对象将用于任何其他客户端.
RemotingServices.Marshal(foo);
Run Code Online (Sandbox Code Playgroud)
Marshal将注册一个由服务器创建的对象,在本例中是一个Windows服务.然后,服务器将引用该对象,并且客户端将使用相同的对象.
我的问题是使用Marshal注册远程对象.随着时间的推移,远程处理对象将消失以供客户端使用,即不再在远程处理对象上.该服务仍将保留其参考.然后我尝试了RegisterWellKnownServiceType并且客户端不断获得正确的引用,但是我无法让服务获得对同一对象的引用.
在这种情况下,解决方案是覆盖远程处理对象FooRemoting.如果我覆盖了InitializeLifetimeService并返回null,则客户端永远不会丢失连接,并且服务将保持连接.
public override object InitializeLifetimeService()
{
//return base.InitializeLifetimeService();
return null;
}
Run Code Online (Sandbox Code Playgroud)
为了保持服务创建的对象并让客户端使用您必须使用的同一对象
RemotingServices.Marshal(foo);
Run Code Online (Sandbox Code Playgroud)
并覆盖InitializeLifetimeService以返回null.
Dan*_*wer 14
可以通过远程处理来显示具有参数构造函数的MarshalByRefObjects,并且该类的用户可以仅处理其接口.
我创建了一个小概念验证项目.它有3个项目:服务器,客户端和核心.服务器和客户端都引用Core但不互相引用.
在核心中,我们定义了一个服务接口:
namespace Core
{
public interface ICountingService
{
int Increment();
}
}
Run Code Online (Sandbox Code Playgroud)
服务器定义具体实现,客户端没有引用:
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
需要注意的重要事项是它有一个带参数的构造函数,它是一个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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码已经注册了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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行服务器和客户端时,它会打印6到10之间的值.
总结:客户端只知道接口; 实现构造函数可以有参数; 实例化可以由您自己的代码而不是.NET控制.在处理基于构造函数的依赖注入和远程处理对象时非常有用.