Events over .Net Remoting
-
Hi all, I have a problem I cannot solve by my own. The message is quite long, but I hope that someone is nice enough to read it and give me a hand. The basic problem is that I cannot sent events over .Net remoting that has an event argument as a class I have created, but strings as arguments works just fine. I have three projects: Server, Middle and Client. Server going to generate events and pass them through .Net remoting to the client. The middle project contains the remoted object. It also contains a delegate that is used to define the events generated in the server. The server is remoting the class in the middle project through a TCP channel. The connection class in the server is remoting the object:
private void OpenConnection() { BinaryClientFormatterSinkProvider clientProvider = null; BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; IDictionary props = new Hashtable(); props["port"] = 7889; props["typeFilterLevel"] = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; props["name"] = "StatusControl"; TcpChannel chan = new TcpChannel( props,clientProvider,serverProvider); ChannelServices.RegisterChannel(chan); RemotingConfiguration.RegisterWellKnownServiceType( Type.GetType("ProductionStatusControl.DistributedStatusControl, ProductionStatusControl"),"IDistributedControl", WellKnownObjectMode.Singleton ); // Singleton class used to retreive messages from the remoted objects m_single = StatusSingletonConnection.GetInstance(); System.Threading.ThreadStart ts = new System.Threading.ThreadStart( SendMessages ); System.Threading.Thread t = new System.Threading.Thread( ts ); t.IsBackground = true; t.Start(); }
The middle project has a delegate:public delegate void ProductionStatusDelegate( StatusMessage message );
, a class as event argument:/// /// A status message from the floating storage /// [Serializable] public class StatusMessage { private FloatingStorageEventType m_type; private string m_message; /// /// Creates a new Status message instance /// /// /// public StatusMessage( FloatingStorageEventType type, string message ) { this.m_message = message; this.m_type = type; }
-
Hi all, I have a problem I cannot solve by my own. The message is quite long, but I hope that someone is nice enough to read it and give me a hand. The basic problem is that I cannot sent events over .Net remoting that has an event argument as a class I have created, but strings as arguments works just fine. I have three projects: Server, Middle and Client. Server going to generate events and pass them through .Net remoting to the client. The middle project contains the remoted object. It also contains a delegate that is used to define the events generated in the server. The server is remoting the class in the middle project through a TCP channel. The connection class in the server is remoting the object:
private void OpenConnection() { BinaryClientFormatterSinkProvider clientProvider = null; BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; IDictionary props = new Hashtable(); props["port"] = 7889; props["typeFilterLevel"] = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; props["name"] = "StatusControl"; TcpChannel chan = new TcpChannel( props,clientProvider,serverProvider); ChannelServices.RegisterChannel(chan); RemotingConfiguration.RegisterWellKnownServiceType( Type.GetType("ProductionStatusControl.DistributedStatusControl, ProductionStatusControl"),"IDistributedControl", WellKnownObjectMode.Singleton ); // Singleton class used to retreive messages from the remoted objects m_single = StatusSingletonConnection.GetInstance(); System.Threading.ThreadStart ts = new System.Threading.ThreadStart( SendMessages ); System.Threading.Thread t = new System.Threading.Thread( ts ); t.IsBackground = true; t.Start(); }
The middle project has a delegate:public delegate void ProductionStatusDelegate( StatusMessage message );
, a class as event argument:/// /// A status message from the floating storage /// [Serializable] public class StatusMessage { private FloatingStorageEventType m_type; private string m_message; /// /// Creates a new Status message instance /// /// /// public StatusMessage( FloatingStorageEventType type, string message ) { this.m_message = message; this.m_type = type; }
Events conceptually are not sound in any network protocol. I'm surprised there was even an attempt in .Net Remoting to support this. The exception you are seeing is somewhat indicitive of the general problem. I wish that future versions of .Net Remoting would throw a more accurate exception than
ArgumentException
you often see in this case. Okay so what is the problem? Mechanically, it can't serialize the delegate and event cleanly across .Net Remoting. Seriously, how would .Net Remoting even begin to handle an delegates/events? Ignore the actual mechanical problems with serialization for a moment and look at the concept you are trying to do. Bare with my crude ascii art :)+--------------------------------------------+ +-------------------+
- Client + + Server +
-
+ + +
- ObjectA CallRemoteB() + ---------------->+ ObjectB Call() +
- { + + { +
- b.ValueChanged += ValueChangeDelegate(); + + DoSomeStuff(); +
- b.Call(); + err??? <--------+ ValueChanged(); +
- } + + } +
+--------------------------------------------- +-------------------+
Remember that the client and server are for all purposes are in two seperate application domains let alone two different processes let a lone two different machines. If you don't understand why marshalling events across seperate app domains is tricky then read on. :) The client is making a call
b.Call
which is remoted and marshalled correctly over to the server. If you don't do anything fancy, it is going to be syncronous and therefore block and wait for the response from the server. Over on the server, it is going to do theObjectB.Call
method when it makes an attempt to do the event. Okay, how does the server contact the client?? If you can't come up with a good answer then you see why events are a problem in Remoting. :) Neither application domain knows what state the other is in. Even if the client is making an asycronous remote call, the client would have to *stop* execution on whatever it is doing and do the event. The client side is either blocked waiting for a response or the client -
Events conceptually are not sound in any network protocol. I'm surprised there was even an attempt in .Net Remoting to support this. The exception you are seeing is somewhat indicitive of the general problem. I wish that future versions of .Net Remoting would throw a more accurate exception than
ArgumentException
you often see in this case. Okay so what is the problem? Mechanically, it can't serialize the delegate and event cleanly across .Net Remoting. Seriously, how would .Net Remoting even begin to handle an delegates/events? Ignore the actual mechanical problems with serialization for a moment and look at the concept you are trying to do. Bare with my crude ascii art :)+--------------------------------------------+ +-------------------+
- Client + + Server +
-
+ + +
- ObjectA CallRemoteB() + ---------------->+ ObjectB Call() +
- { + + { +
- b.ValueChanged += ValueChangeDelegate(); + + DoSomeStuff(); +
- b.Call(); + err??? <--------+ ValueChanged(); +
- } + + } +
+--------------------------------------------- +-------------------+
Remember that the client and server are for all purposes are in two seperate application domains let alone two different processes let a lone two different machines. If you don't understand why marshalling events across seperate app domains is tricky then read on. :) The client is making a call
b.Call
which is remoted and marshalled correctly over to the server. If you don't do anything fancy, it is going to be syncronous and therefore block and wait for the response from the server. Over on the server, it is going to do theObjectB.Call
method when it makes an attempt to do the event. Okay, how does the server contact the client?? If you can't come up with a good answer then you see why events are a problem in Remoting. :) Neither application domain knows what state the other is in. Even if the client is making an asycronous remote call, the client would have to *stop* execution on whatever it is doing and do the event. The client side is either blocked waiting for a response or the clientHi! Thank you for you reply! I realize that what I was trying to do was not as easy or smart as I thought.. What puzzles me is that it works well if I use a delegate with only a string as a argument. Why does that work?? I cannot have a delegate with two strings as arguments, but one work. I tried to implement the ISerializable interface. That did not work either. I can buy the thought of the events not working if the server cannot find the client, that is reasonable. But why does it work if the argument is a string?? :confused: Best Regards Mikke
-
Hi! Thank you for you reply! I realize that what I was trying to do was not as easy or smart as I thought.. What puzzles me is that it works well if I use a delegate with only a string as a argument. Why does that work?? I cannot have a delegate with two strings as arguments, but one work. I tried to implement the ISerializable interface. That did not work either. I can buy the thought of the events not working if the server cannot find the client, that is reasonable. But why does it work if the argument is a string?? :confused: Best Regards Mikke
Consider what is happening when you "sign up" for the event. You need to send a message to the server object to add
ClientObject.ClientFunction
to the delegate list. AssumingClientObject
is aMarshalByRefObject
, it can marshal "itself" across. It can also marshalstrings
across. So technically it will succeed in making the functional call across the .Net Remoting. The problem is that it is meaningless to the server app domain because of all of the stuff I meantioned before. All of the object references only work in the client domain and will "blow up" if used in server domain. Oh yeah, I did mention a way to work around the limitation in .Net Remoting but it might not be clear without an example:ObjectA CallRemoteB()
{
/* old bad way
b.ValueChanged += ValueChangeDelegate();
b.Call();
*/
// better way: sometime earlier the object signed up for the delegate like so
// this.ValueChanged += new ValueChangedDelegate(this.onValueChanged());
b.Call();
if(this.ValueChanged != null)
this.ValueChanged();
}The event/delegate is now only in the client app domain so everything works.