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

Dav*_*rab 17 .net c# remoting

在.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控制.在处理基于构造函数的依赖注入和远程处理对象时非常有用.