Discussion:
Remoting Delegates and events
(too old to reply)
Steven Rosenberg
2008-04-15 14:40:39 UTC
Permalink
I am trying to create a remote class that will allow a client to subscribe
to an event using delegates in C#. I have tried to do this my setting up a
class that is marshaled by reference to be used as the object that handles
the event

public delegate void RemoteAlert(string str);

public abstract class RemoteHandlerBase : MarshalByRefObject
{
public void Alert(string s)
{
//override on client is required
HandleAlert(s);
}

abstract protected void HandleAlert(string s);
}



The following class manages the actual delegate creation and fireing of the
event:

public class RemoteAlerter: MarshalByRefObject
{
#region public attributes and methods.
public event RemoteAlert RemoteAlertEvent;

//constructor...required if event object is used within a singleton
public RemoteAlerter()
{
Console.WriteLine("RemoteAlerter constructor.");
}

public void SetAsSubscriber()
{
EventSubscribers.Add(this); //add subscriber to list
}

public bool FireAlert(string s)
{
//if there are subscribers to the published events
if ( RemoteAlertEvent != null && EventSubscribers.Count > 0)
{
Console.WriteLine("# of subscribers = {0}.",
EventSubscribers.Count);
for (int i = 0; i < EventSubscribers.Count; i++)
{
((RemoteAlerter)(EventSubscribers[i])).RemoteAlertEvent(s);
}

return true;
}
return false;

}

#endregion

#region private attributes and methods.

private ArrayList EventSubscribers = new ArrayList(); //required for
singleton use

#endregion

}



The name of the inherited class that contains the event handler is...

class RemoteHandler : IProcessActivator_ClientActivated.RemoteHandlerBase
{
override protected void HandleAlert(string msg)
{
Console.WriteLine("Alert from server: {0}", msg);
}
}



When I instantiate the inherited class on the client side no execeptions are
thrown. When I create an event...

RemoteAlerter alert = (RemoteAlerter)Activator.GetObject(typeof
(IProcessActivator_ClientActivated.RemoteAlerter),

"tcp://localhost:9000/RemoteAlerter");

RemoteHandler rh = new RemoteHandler();
alert.RemoteAlertEvent += new RemoteAlert(rh.Alert);

...again no execeptions are thrown, however when the event is fired on the
server it is never received by the client.

The connection to the remote class uses a TCP / Binary connection method

Any ideas?
Charlie Rundles
2008-04-22 16:33:01 UTC
Permalink
Hi Steven,

I tried the same thing--I believe you're trying to implement the Observer
pattern.
This is not simple--I've have not quite figured out how to do so.
Existing examples implement "chat room" patterns, where one client can post
messages to other clients--the server only relays messages from a
subscription list it maintains.

Anyhow, the answer to your question: the subscribers have a new instance of
a "singleton". Your server has it's own instance. The two are not the same.
The server is generating events that no one is listening to, and the
listeners are listening on a singleton to which no one posts events.
However, try having any client post an event to that remoted singleton. You
should see an event appear to all clients.

So, the problem that I've not yet solved: how to get the server access to
that same instance. It would be ridiculous to require the server to connect
to itself.

The basic problem is how to implement the Observer pattern using Remoting,
and it may turn out that Remoting is not up to that simple task.
Post by Steven Rosenberg
I am trying to create a remote class that will allow a client to subscribe
to an event using delegates in C#. I have tried to do this my setting up a
class that is marshaled by reference to be used as the object that handles
the event
public delegate void RemoteAlert(string str);
public abstract class RemoteHandlerBase : MarshalByRefObject
{
public void Alert(string s)
{
//override on client is required
HandleAlert(s);
}
abstract protected void HandleAlert(string s);
}
The following class manages the actual delegate creation and fireing of the
public class RemoteAlerter: MarshalByRefObject
{
#region public attributes and methods.
public event RemoteAlert RemoteAlertEvent;
//constructor...required if event object is used within a singleton
public RemoteAlerter()
{
Console.WriteLine("RemoteAlerter constructor.");
}
public void SetAsSubscriber()
{
EventSubscribers.Add(this); //add subscriber to list
}
public bool FireAlert(string s)
{
//if there are subscribers to the published events
if ( RemoteAlertEvent != null && EventSubscribers.Count > 0)
{
Console.WriteLine("# of subscribers = {0}.",
EventSubscribers.Count);
for (int i = 0; i < EventSubscribers.Count; i++)
{
((RemoteAlerter)(EventSubscribers[i])).RemoteAlertEvent(s);
}
return true;
}
return false;
}
#endregion
#region private attributes and methods.
private ArrayList EventSubscribers = new ArrayList(); //required for
singleton use
#endregion
}
The name of the inherited class that contains the event handler is...
class RemoteHandler : IProcessActivator_ClientActivated.RemoteHandlerBase
{
override protected void HandleAlert(string msg)
{
Console.WriteLine("Alert from server: {0}", msg);
}
}
When I instantiate the inherited class on the client side no execeptions are
thrown. When I create an event...
RemoteAlerter alert = (RemoteAlerter)Activator.GetObject(typeof
(IProcessActivator_ClientActivated.RemoteAlerter),
"tcp://localhost:9000/RemoteAlerter");
RemoteHandler rh = new RemoteHandler();
alert.RemoteAlertEvent += new RemoteAlert(rh.Alert);
....again no execeptions are thrown, however when the event is fired on the
server it is never received by the client.
The connection to the remote class uses a TCP / Binary connection method
Any ideas?
Kevin J. Stricklin
2008-05-19 16:49:04 UTC
Permalink
I'm guessing you have registered RemoteHandlerBase as a wellknown object in
your server application -- probably as a singleton. The problem doing this is
that the Remoting infrastructure will create an instance of RemoteHandlerBase
for you. This instance will be different from the one you create when you
call new RemoteHandlerBase().

The solution is to NOT register RemoteHandlerBase as a wellknown object.
Rather, after creating your instance of RemoteHandlerBase, make it available
to your clients by calling RemotingServices.Marshal()

Loading...