What you want is somehow to access the instance of ServiceConsoleHandler
via a RemoteObject
instance, which is visible for the client.
For this you need to consider two things: (1) Get control over the object construction of the RemoteObject
instance and make it accessible and (2) modify ServiceConsoleHandler
so it can be accessed remotely.
(1)
How would you construct a RemoteObject
instance in ServiceConsoleHandler
, if you don’t need to consider remoting?
I guess you would do something like this:
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;
…
}
It would be nice if you could make this object accessible for the client. You can do this by using RemotingServices.Marshal instead of 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");
…
}
(2)
If you execute the code right now and access the remoteObject.Server
in the client code you would get some remoting exception, because the class ServiceConsoleHandler
cannot be accessed remotely. Therefore you need the add the [Serializable]
attribute:
[Serializable]
class ServiceConsoleHandler
{ … }
Reason: Types which should be accessed remotely, need to be marshaled to some special transferrable representation. This way they can be squeezed through the TCP port and transferred via the TCP protocol. Basic data types can by marshaled by the framework, so you don't need to think about them. For custom types you will need to state, how to do this. One way to do this is by subclassing from MarshalByRefObject
. That’s exactly what you have already done with RemoteObject
. Another way is to mark your custom classes as [Serializable]
as shown above.
That’s it. Now you should be able to access the server’s field in the client code. Note that you don’t need your existing code for object activation:
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);
For me .NET remoting is full of funny surprises and sleepless nights. To counter this, make yourself familiar with the remoting concepts (which are from my point of view poorly documented). Dig into the serialization concept (MarshalByRefObject
vs. [Serializable]
). If you want to make a production code out of it, think a very good ways to handle remoting exceptions. Also consider multithreading. There could be more than one client using this remote object at once.
Have fun!