Подтвердить что ты не робот

В .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);
4b9b3361

Ответ 1

Это то, что я нашел.

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

RegisterWellKnownServiceType создаст объект и сделает его Singleton для любого клиента, который его использует, но ссылка на сервер не создается. Объект не создается до тех пор, пока клиент не попросит об этом, и тот же объект используется для других клиентов.

RemotingServices.Marshal(foo);

Маршал зарегистрирует объект, созданный сервером, в данном случае - службу Windows. Затем сервер будет ссылаться на объект, и клиенты будут использовать один и тот же объект.

Моя проблема заключалась в использовании маршала для регистрации удаленного объекта. Со временем удаленный объект исчезнет для клиентов, чтобы потреблять, т.е. Больше не удалять объект. Служба все равно сохранит свою ссылку. Затем я попробовал RegisterWellKnownServiceType, и клиенты продолжали получать правильную ссылку, однако я не мог заставить службу иметь ссылку на тот же объект.

В этом случае решение переопределяет удаляемый объект FooRemoting. Если я переопределяю InitializeLifetimeService и вернул null, клиент никогда не потеряет соединение, и служба будет, сохраните соединение.

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

Чтобы сохранить объект, созданный службой, и чтобы клиент использовал тот же объект, вы должны использовать

RemotingServices.Marshal(foo);

и переопределить InitializeLifetimeService для возврата null.

Ответ 2

Можно вывести 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. Очень полезно при работе с инъекцией зависимостей на основе конструктора с удаленными объектами.

Ответ 3

Я сделал один эксперимент с 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, вы увидите, что конструктор получает вызов 2 раза

  • Когда объект RemoteClass создается в самой службе
  • Когда клиент выполняет вызов свойства MyVal.

Я думаю, RemotingServices.Marshal не имеет ничего общего с единственным экземпляром. Даже если вы используете только RemotingConfiguration.Configure и переопределите InitializeLifetimeService, чтобы он возвращал значение null, будет достаточно, чтобы разместить удаленный компонент.