.NET Remoting: как получить доступ к объектам приложения сервера из удаленного объекта? - PullRequest
2 голосов
/ 19 января 2009

Я пишу приложение службы Windows, к которому можно получить доступ через .NET Remoting. Проблема в том, что я не могу понять, как получить доступ к сервисным объектам из удаленного класса.

Например, у меня есть класс обработчика:

class Service_console_handler
   {
    public int something_more = 20;

    //some code...

            TcpChannel serverChannel = new TcpChannel(9090);
            ChannelServices.RegisterChannel(serverChannel);
            RemotingConfiguration.RegisterWellKnownServiceType(
                        typeof(RemoteObject), "RemoteObject.rem", 
                        WellKnownObjectMode.Singleton);

    //from here on RemoteObject is accessible by clients.
    //some more code doing something and preparing the data...
   }

И у меня есть класс удаленного доступа:

public class RemoteObject : MarshalByRefObject
{
    private int something = 10;

    public int Get_something()
    {
        return something;
    }
}

Клиенты могут без проблем получать доступ к данным в RemoteObect. Но как я могу получить доступ к Service_console_handler объекту (т.е. получить полезную информацию из something_more)?

Извините за глупые вопросы и заранее спасибо.

Ответы [ 2 ]

6 голосов
/ 21 января 2009

Вам нужно как-то получить доступ к экземпляру ServiceConsoleHandler через экземпляр RemoteObject, который виден для клиента.

Для этого вам необходимо учесть две вещи: (1) получить контроль над созданием объекта экземпляра RemoteObject и сделать его доступным, (2) изменить ServiceConsoleHandler, чтобы к нему можно было получить удаленный доступ.

(1)

Как бы вы создали RemoteObject экземпляр в ServiceConsoleHandler, если вам не нужно учитывать удаленное взаимодействие?

Полагаю, вы бы сделали что-то вроде этого:

class ServiceConsoleHandler
{
   …
   RemoteObject remoteObject = new RemoteObject();
   // now assume that you also already have
   // modified the RemoteObject class so it can hold
   // a reference to your server:
   remoteObject.Server = this;
   …
}

Было бы неплохо, если бы вы могли сделать этот объект доступным для клиента. Вы можете сделать это, используя RemotingServices.Marshal вместо RemotingConfiguration.RegisterWellKnownServiceType:

class ServiceConsoleHandler
{
     …
     TcpServerChannel channel = new TcpServerChannel(9090);
     ChannelServices.RegisterChannel(channel, true);
     RemoteObject remoteObject = new RemoteObject();
     remoteObject.Server = this;
     RemotingServices.Marshal(remoteObject, "RemoteObject.rem");
     …
}
* * 1 022 (2)

Если вы выполните код прямо сейчас и получите доступ к remoteObject.Server в клиентском коде, вы получите исключение удаленного взаимодействия, поскольку к классу ServiceConsoleHandler нельзя получить удаленный доступ. Поэтому вам нужно добавить атрибут [Serializable]:

[Serializable]
class ServiceConsoleHandler
{ … }

Причина: типы, к которым следует обращаться удаленно, должны быть преобразованы в какое-то специальное передаваемое представление. Таким образом, они могут быть сжаты через порт TCP и переданы по протоколу TCP. Базовые типы данных могут быть упорядочены структурой, поэтому вам не нужно думать о них. Для пользовательских типов вам нужно указать, как это сделать. Один из способов сделать это - создать подкласс от MarshalByRefObject. Это именно то, что вы уже сделали с RemoteObject. Другой способ - пометить ваши пользовательские классы как [Serializable], как показано выше.

Вот и все. Теперь вы сможете получить доступ к полю сервера в коде клиента. Обратите внимание, что вам не нужен существующий код для активации объекта:

        TcpClientChannel channel = new TcpClientChannel();
        ChannelServices.RegisterChannel(channel, true);

        RemoteObject remoteObject = (RemoteObject)Activator.GetObject(
            typeof(RemoteObject), "tcp://localhost:9090/RemoteObject.rem");

        Console.WriteLine(remoteObject.Server.SomethingMore);

Для меня .NET Remoting полон забавных сюрпризов и бессонных ночей. Чтобы противостоять этому, ознакомьтесь с концепциями удаленного взаимодействия (которые, с моей точки зрения, плохо документированы). Окунитесь в концепцию сериализации (MarshalByRefObject против [Serializable]). Если вы хотите сделать из него производственный код, подумайте об очень хороших способах обработки исключений удаленного взаимодействия. Также рассмотрим многопоточность. Может быть несколько клиентов, использующих этот удаленный объект одновременно.

Веселись!

0 голосов
/ 21 января 2009

Спасибо! Я очень ценю тщательность и четкость вашего ответа.

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

Теперь удаленное взаимодействие выглядит гораздо более полезным для меня. Я только что написал быстрое тестовое приложение, и оно сработало. Еще раз спасибо.

...