В чем разница между RemotingConfiguration.RegisterWellKnownServiceType и RemotingServices.Marshal в удаленном взаимодействии .NET?

В чем разница между RemotingConfiguration.RegisterWellKnownServiceType и RemotingServices.Marshal в удаленном взаимодействии .NET?

Что я хочу сделать, так это создать объект в службе Windows, затем поместить его в качестве удаленного объекта и заставить службу Windows и клиент воздействовать на удаленный объект.

Я думал, что приведенный ниже код выполнит это.

FooRemoting foo = new FooRemoting();

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

person David Basarab    schedule 29.01.2009    source источник


Ответы (3)


Вот что я нашел.

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.

person David Basarab    schedule 29.01.2009
comment
Идеальный ответ. именно то, чего мне не хватало. - person Mo Valipour; 06.06.2014
comment
Не говоря уже о справочной проблеме, есть еще одно отличие, которое я заметил здесь: при использовании RemotingServices.Marshal все изменения его свойств, регистрация событий сохраняются (это означает, что любой вызов от клиента может вызвать какое-то событие в объекте службы,...) Но при использовании RegisterWellKnownServiceType у меня нет возможности зарегистрировать какое-то конкретное событие или изменить какое-то определенное свойство созданного объекта (у нас даже нет доступа к этому созданному объекту?), то есть все должно быть сделано внутри класса объекта. - person Hopeless; 05.09.2015

Можно предоставить MarshalByRefObjects, которые имеют конструкторы с параметрами, вместо удаленного взаимодействия, и пользователи класса могут иметь дело только с его интерфейсом.

Я создал небольшое доказательство концепции проекта. Он имеет 3 проекта: сервер, клиент и ядро. Сервер и клиент ссылаются на ядро, но не ссылаются друг на друга.

В ядре мы определяем сервисный интерфейс:

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

person Daniel Flower    schedule 21.01.2010
comment
Спасибо, что собрали весь этот образец вместе. Прошло много времени с тех пор, как я занимался удаленным взаимодействием, и эта публикация стала для меня очень хорошим напоминанием. Спасибо чувак! - person justin.lovell; 09.10.2011

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

person Community    schedule 01.07.2009