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

发布于 2024-07-12 02:46:53 字数 417 浏览 4 评论 0原文

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

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

我认为下面的代码可以完成此任务。

FooRemoting foo = new FooRemoting();

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

In .NET remoting what is the difference between RemotingConfiguration.RegisterWellKnownServiceType and RemotingServices.Marshal?

What I want to do is create an object in a Windows Service, then put it in as a remoting object and have the Windows Service and the Client both act on the remoting object.

I thought the below code would accomplish this.

FooRemoting foo = new FooRemoting();

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

深海夜未眠 2024-07-19 02:46:53

这就是我发现的。

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

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

RemotingServices.Marshal(foo);

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

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

解决方案是覆盖远程对象(在本例中为 FooRemoting)。 如果我覆盖 InitializeLifetimeService 并返回 null,客户端将永远不会失去连接,并且服务将,
保持连接。

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

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

RemotingServices.Marshal(foo);

并重写 InitializeLifetimeService 以返回 null。

This is what I found.

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

RegisterWellKnownServiceType will create the object and make it a Singleton to any client that consumes it, but a reference by the server is not created. The object is not created until a client ask for it, and the same object is used for any other clients.

RemotingServices.Marshal(foo);

Marshal will register an object that has been created by the server, in this case a windows service. Then server will then have reference to the object and the clients will consume the same object.

My issue was using the Marshal to register the remoting object. Over time the remoting object will disappear for clients to consume, i.e. no longer on the remoting object. The service would still keep its reference.
Then I tried the RegisterWellKnownServiceType and the clients keep getting the correct reference, however I could not get the service to have a reference to the same object.

The solution is overriding the remoting object in this case FooRemoting. If I overrode the InitializeLifetimeService and returned null, the client would never lose connection, and the service will,
keep the connection.

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

In order to keep the object created by the service and have the client to use the same object you must use

RemotingServices.Marshal(foo);

and override InitializeLifetimeService to return null.

吻风 2024-07-19 02:46:53

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

我创建了一个小型概念验证项目。 它有 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 来控制。 在处理远程对象的基于构造函数的依赖注入时非常有用。

It is possible to expose MarshalByRefObjects which have parameterful constructors over remoting, and it's possible for users of the class to only deal with its interface.

I have created a small proof of concept project. It has 3 projects: Server, Client, and Core. Server and Client both reference Core but do not reference each other.

In core, we define a service interface:

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

The server defines the concrete implementation, which the client doesn't have a reference to:

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;
        }
    }
}

The important bits to note are that it has a constructor with a parameter, it is a MarshalByRefObject, and it implements the interface in the core project.

The server project is a console app which sets up a remoting channel (arbitrarily over HTTP for this example), creates the service, and registers it with remoting:

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();
        }
    }
}

The above code has registered the URL http://localhost:8234/CountingService.rem which holds the instantiated service, which will start counting from 5.

The client, also a console app, can then get a reference, using the interface class:

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();
        }
    }
}

When the server and client are run, it prints values from 6 to 10.

Summary: client knows only about the interface; implementation constructor can have parameters; instantiation can be controlled by your own code rather than by .NET. Very useful when dealing with constructor-based dependency injection with remoting objects.

如果没有你 2024-07-19 02:46:53

我用 RemotingServices.Marshal 做了一项实验,就像

托管在 Windows Exe 中的远程组件一样。 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的构造函数中放置断点,您将看到

  1. 当在Service中创建RemoteClass对象时 。
  2. 构造函数被调用2次当客户端调用 MyVal 属性时

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

I did one experiment with RemotingServices.Marshal like this

Remotable component hosted in a Windows Exe. Exe code is

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;
   }
 }       
}

Now in the client side code

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

It will popup the message as 0 not 100. If you put a breakpoint in the constructor of RemoteClass, you will see that the constructor is getting called 2 times

  1. When the RemoteClass object is created in the Service itself
  2. When the client is making call to MyVal property.

I think RemotingServices.Marshal has nothing to do with the single instance. Even if you use just RemotingConfiguration.Configure and override the InitializeLifetimeService so that it will return null, will be sufficient to host a remotable component.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文