tags:

views:

847

answers:

2

Hello!

I'm writing a windows service application, which will be accessed through .NET Remoting. The problem is I can't figure out how to access service objects from remotable class.

For example, I've a handler class:

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

And I've a remotable class:

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

    public int Get_something()
    {
        return something;
    }
}

Clients can access data in RemoteObect with no problem. But how can I access Service_console_handler object (i.e. to retrieve useful info from something_more)?

Sorry for dumb questions and thanks in advance.

A: 

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!

Theo Lenndorff
A: 

Thank you! I very much appreciate thoroughness and clarity of you answer.

Most bizzare thing is that I didn't even know that you can publish object instance. About a dozen simple tutorials I studied proposed RemotingConfiguration.RegisterWellKnownServiceType as only method to do remoting. Stupid me.

Now remoting looks much more useful to me. I just wrote a quick test application and it worked. Thanks again.