.NET Framework Bookmark and Share   
 index > .NET Remoting and Runtime Serialization > Is .NET Remoting Bidirectional in .NET 2.0?
 

Is .NET Remoting Bidirectional in .NET 2.0?

I am in the process of deciding which technology to use for our new application.

Does .NET Remoting TCP or HTTP channel support bidirectional communication?

I am going to use Singleton SAO which is stateful.

Dynamic
Hello,

Yes, remoting is bidirectional.
The way I always solve this is by first creating a SAO singleton.
Then, each client will have to createits ownCAO.
Register this CAO with the SAO (the SAO is shared for all clientsand contains a list of registered CAO's).
When the server needs to contact a client, it can loop through its list of CAO's to search the right one.
Then, the SAO can call one of the CAO's methods.

But keep in mind that remote objects have a lifetime.
So,you should either set the object's lifetime to infinite, or let the clients make a call every 10 minutes or so.
Default lifetime is 15 minutes, you can alter it by overriding 'InitializeLifetimeService'

Hope this helps
Stefan
Stefan H.F. A.
Many thanks Stefan; very good idea it seems

So my understanding is thaton the server I should create a TCPServerChannel for Singleton SAO and a TCPClientChannel for the CAO
On the client desktop app I will create a TCPClientChannel for the Singleton SAO and a TCPServerChannel for the CAO.

On my Singleton SAO remoting object I will have a method such as AttachClient() which accepts the CAO object as input parameter and saves it to its list of clients property.

How scalable is this? We will eventually have about 25000 clients, so 25000 CAO Remoting objects will be created...

Thanks,
Dynamic

Hi,

actually you only need to declare one single channel.
A TCPServerChannel is for the service, and TCPClientChannel for the client (as their names imply).
Both the SAO and the CAO can be used on the same channel.

Personally I'd advise you use a configuration file if you can.
This will allow you to change channel settings without having to redeploy.
So, this might be extra interesting if you have many clients!
Also, itwill require only one line of code:RemotingConfiguration.Configure("MyApp.exe.config");
The config file should contain the node <system.runtime.remoting> and subnodes.
You can find more info about this in MSDN.
(maybe http://msdn.microsoft.com/en-us/library/ms973907.aspxcan help you, I haven't read it myself though)

If you want to speed up the client registration, you could store the client registrations in a Dictionary.
Then, if you're searching for a specific client, you canuse its key to search for it.
e.g. Client A wants to say something to client B, client A will say to the server (the SAO): "will you say 'something'to the client with ID x for me?"
Server can search for ID x in its dictionary, by simply calling _myClients[x]
The dictionary returns the CAO, and then you can call its method.
Of course, this would require client A to know the ID for client B.
But an ID could be a GUID or integer, whichis a value type and as such isfreely distributable across all clients.

If the server needs to communicate to ALL clients, you shoulduse .GetEnumerator

Kind regards,
Stefan

Stefan H.F. A.
This is very interesting; thanks Stefan.

My understanding is:

So what you mean is that if a remote object has been activated using CAO, it can call back to the client object?! I am not sure about this? How could it be possible since there is no client object on the server. the CAO object on the server is just an instance on the server not on the client. Client has just call that instancenot vice versa; or my knowledge is not enough at this stage...

Moreover, I don't thinkTCPServerChannel can act as a client of TCPClientChannel...

Assuming the way you suggested is possible, that I don't know how yet, then I think having both TCPServerChannel and TCPClientChannel on the Server Machine and Client Machine would be more scalable since the CAO instances in that case would be saved on the client machines and the server machine only holds a reference to them; less memory consumption by server considering I will eventually have over 25000 clients...

I appreciate your thoughts about this.
Dynamic

Hi,

OK, I think I'll have to explain the basic workings of .NET remoting here.
if you create a remote object,then there are actually 2 'objects' that are created.
The actual object is always stored server side.
Then, another object is created, called the proxy, which is kept client side.
This is always true, for both SAO and CAO objects.
This proxy is actually nothing more than a gateway to the real object, the one kept server side.
The proxy behaves as if it were the real thing.

Now, the difference between a SAO singleton and a CAO is that, if a method is executed on the object, a SAO method executes server-side, and a CAO method executes client side (on the proxy).


So, if you write the following line of code (suppose MyClient is a CAO remotable type):

MyClient mc = new MyClient();

Remember that 2 objects are created; the actual object and the proxy.
Note that this line of code is executed client side.
The mc variable is now the proxy, you see?

if the server now calls a method, that method is executed on the mc variable client side.

So, if you understand this you should see that the service is always the server, and therefore you should create a Server channel.
Same goes for client and Client channel.

By the way, I'm quite sure this way is possible because I'm using this technique myself ;-)

Stefan H.F. A.

I can't agree wrt what you said about the difference between a CAO and a SAO.

Both CAO and SAO are executed on the server side and are initated by the client side through the client proxies like WCF Services and Web Services. The difference is that in case of SAO, server controls the life time of the created object which could be either singleton or singlecall and in the case of CAO, client initiates and controls the life time of the object which is created on the server side (behaves like a Session in WCF). Have a look at this sample.

"if the server now calls a method, that method is executed on the mc variable client side."

How server can call a CAO method of the client machine?! unless the server side acts as a client, e.g. via introducing TCPClientChannel, it can't initiate sending any message to the client machine, or I can't imagine how it does so...

Do you have any source code about what you mean?

Thanks,



Dynamic
Try this out:

1) Create a new blank solution
2) Add 3 projects: 1 console app called 'Service', 1 console app called 'Client', 1 class library called 'Library'
3) Add references to System.Runtime.Remoting in Service and Client project
4) Add reference to Library in Service and Client project
5) In the Library project add 2 interfaces: ISAO and ICAO. Code for these 2 interfaces are:

using System;
namespace Library
{
public interface ICAO
{
void CallCAO();
}
}

using System;
namespace Library
{
public interface ISAO
{
int AmountOfClients { get; }

void RegisterCAO(ICAO cao);
}
}

6) In the Client project, Add 2 files: CAO.cs and app.config

using System;
using Library;
namespace Client
{
public class CAO : MarshalByRefObject, ICAO
{
public void CallCAO()
{
Console.WriteLine("Notifying CAO");
}
}
}

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client url="tcp://localhost:9000">
<activated type="Library.CAO, Library" />
<wellknown type="Library.ISAO, Library" url="tcp://localhost:9000/SAO.rem" />
</client>
<channels>
<channel ref="tcp" port="0" >
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

7) Alter the Program.cs from the Client project

using System;
using System.Runtime.Remoting;
using Library;
namespace Client
{
class Program
{
static void Main(string[] args)
{
RemotingConfiguration.Configure("Client.exe.config", false);

Console.WriteLine("This is the client\r\n");

System.Threading.Thread.Sleep(500);

ISAO sao = (ISAO)Activator.GetObject(typeof(ISAO), "tcp://localhost:9000/SAO.rem");

CAO cao = new CAO();
sao.RegisterCAO(cao);

Console.WriteLine("CAO has been added to SAO\r\n");

Console.ReadLine();
}
}
}

8) In the SERVICE project, add 2 files: SAO.cs and app.config

using System;
using System.Collections.Generic;
using System.Text;

using Library;

namespace Service
{
public class SAO : MarshalByRefObject, ISAO
{
private List<ICAO> _clients;

public int AmountOfClients { get { return _clients.Count; } }

public SAO()
{
_clients = new List<ICAO>();
}

public void RegisterCAO(ICAO cao)
{
_clients.Add(cao);
}

public void NotifySAO()
{
Console.WriteLine("Notifying SAO");
}

public void NotifyCAO()
{
foreach (ICAO cao in _clients)
cao.CallCAO();
}
}
}


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<service>
<activated type="Library.ICAO, Library" />
<wellknown mode="Singleton" type="Service.SAO, Library" objectUri="SAO.rem" />
</service>
<channels>
<channel ref="tcp" port="9000" >
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

9) In the Service project, alter the Program.cs

using System;
using System.Runtime.Remoting;
using Library;

namespace Service
{
class Program
{
static void Main(string[] args)
{
RemotingConfiguration.Configure("Service.exe.config", false);

Console.WriteLine("This is the service\r\n");

SAO sao = new SAO();
RemotingServices.Marshal(sao, "SAO.rem", typeof(SAO));

Console.WriteLine("There are " + sao.AmountOfClients + " clients registered.");
System.Threading.Thread.Sleep(1000);
Console.WriteLine("There are " + sao.AmountOfClients + " clients registered.\r\n");

// Notice where the string 'Notifying SAO' pops up
sao.NotifySAO();

// Notice where the string 'Notifying CAO' pops up
sao.NotifyCAO();

Console.ReadLine();
}
}
}

10) Now right click solution -properties -check Multiple start-up projects
11) Set 'Start' for Client and Service
12) Run the program

13) Notice that, even though the SERVICE calls sao.NotifyCAO(); theactual Console.WriteLineis executed on the CLIENT window !

Et voila, you just created service-to-client communication.

Hope this helps,
Stefan

Stefan H.F. A.
Have a look at this:http://www.codeproject.com/KB/IP/c_sharp_remoting.aspx

For example; when the Notify method is called, it doesn't notify the client directly but it just updates the relevant CAO on the server. Then client has to do Polling to get its latest status using a Timer control.

I can't and don't want to use Polling; I need to be able to call the client from server whenever server wants to.
Dynamic
The sample I just posted doesn't use a Timer at all.
Stefan H.F. A.
This is very interesting; I really appreciate it.

I see why it works this way:

When we create a new instance of CAO on the client:

CAO cao = new CAO();
1. A proxy instance of type CAOis created on the client side
2. The CAO remotable object is created on the server through the proxy
3.a proxy incao variable is a reference to that proxy instance.

When we register an ICAO on the server:

public void RegisterCAO(ICAO cao)
{
_clients.Add(cao);
}

what we do is that we pass the reference to the CAO proxy instance to the RegisterCAO method on the server

Then when we say:

public void NotifyCAO()
{
foreach (ICAO cao in _clients)
cao.CallCAO();
}

1. we call the CallCAO method of the CAO proxy instance on the client
2. the proxy will call the CAO object which is on the server

************************

This way is great and works (and probably I will use it)but at the same time it has one extra roundtrip, do you see?

Whencao.CallCAO() is called on the server:
1. Server calls back to the proxy instance on the client machine
2.The proxy instance on the client machine calls the CAO object on the server machine
3. The result of the call is returned back to the client machine

************************

The way I suggested (making both Server Machine and Client Machine to act as Server and Client both)doesn't have this extra roundtrip but needs an extra setup (server needs to know the machine name of each client to create the connections dynamically).

Performance-wise: approach2 may be better because it doesn't have that extra roundtrip
Memory-wise: approach2 is better because the CAO objects will be created on the client and server only keeps a reference to them
Setup/Implementation/Channel-wise: approach 1, what you suggested, is easier.
Dynamic

You can use google to search for other answers

Custom Search

More Threads

• Does my proxy implements myinterface ?
• Remote client managment
• Deserializing-giving lot of pain
• Discovering serialized objects on a network stream
• how can server send objects to clenit (vb.net)
• inter-process communication in .NET - weird problem
• How to know the list of machines a person is logged in an Active Directory ?
• Serialization Optimization
• Getting a class recognized across two processes
• VERY slow binary serialization of strings coming from SQL