Selective events
I have a server with clients. The clients each get a unique Id from the server. Each client knows about the other connected clients Ids.
I want the client to raise an event in other clients. I don't want all the clients to receive the events, but only selected ones.
A simple example: I have a chat program. There are 100 clients, each is involved in a chat with exactly one other clients (50 pairs). When a client want to send a message it raises an event on the server, and only the client in the chat receive this message.
By raising an event normally all clients will need to check if the event is relevant for them. I don't want the event to be raised in the first place, and I only ant to add the code to the server and not in the listening client.
How to do that? Any suggestions?
[832 byte] By [
jhammer] at [2007-11-19 14:08:21]

# 1 Re: Selective events
You can have server controll what cleints receive event. I guess you can try to use ManualResetEvent if you are using cleints on different threads. Just a guess of mine. I am not sure how cleints communicate with the server in your case but if it is clioent server, just send messages to only selected cleints that is controlled by server
# 2 Re: Selective events
But we are talking about events, not just regular messages. Each client register for the event, but if the server needs it invokes the event only in certain clients. This effect I don't know how to acheive.
# 3 Re: Selective events
What is the condition to invoke only certain/selected clients?
# 4 Re: Selective events
Does it really matter? If so, then a possible scenario is to let the client pass the IDs of clients it wants to raise event in to the server, and server will invoke the event selectively. Lets assume that each client and of course the server has the unique ID of other clients. (The ID type is not important - but it is unique for each client).
How does the selective event can be done?
# 5 Re: Selective events
AFAIK, .NET does not support selective event raising. Only workaround I can think of is, let the server register an event handler in all clients. Clients raise this event with client ids as event args. Then server event handler dynamically add clients to the actual event and raise the event.
Something like the following:
private void Server_ListenForClient(Object sender, ServerEventArg e)
{
if (eventArg.EventType == SomeEvent)
{
// use the client ids to retrieve the client object. add all event handler like this
this.SomeEvent += new SomeEventHandler(clientObject.SomeEventHandler);
// raise the event
}
else if (<Some Other event code>)
{
}
// flow will return here after all the event handlers are done.
// remove the events handlers you added just above.
}
public SomeServerMethod(client c, EventType someInterestedEvent)
{
.....
}
// Event arg class.
public class ServerEventArg
{
private EventType eventToBeRaisedType; << Event Type is an enum
private int[] clientIDs;
.......................
}
I know this looks very dirty but that is the only workaround I can think of :)
[Updated] You could add a public method in Server class that could be called from the client instead of raising an event to the server.
# 6 Re: Selective events
ok. It seems possible with straight forward way if we learn how to use Delegate.GetInvocationList() method. Please use Reflection decompiler and see how it invokes a method in your client class. Check the MulticastDelegate and Delegate classes (Delegate.Method, Delegate.Target are the one we need to be looking to).
# 7 Re: Selective events
You could add a public method in Server class that could be called from the client instead of raising an event to the server
That's exactly what I am doing.
It seems possible with straight forward way if we learn how to use Delegate.GetInvocationList() method. Please use Reflection decompiler and see how it invokes a method in your client class. Check the MulticastDelegate and Delegate classes (Delegate.Method, Delegate.Target are the one we need to be looking to).
Thats the direction I thought of. The problem is I could not find even one good resource which will tell me how to use GetInvocationList method in order to check which client belongs the event.
I thought maybe to map the client ID with the event handlers, but I don't know what to map, and when is the mapping should be done.
# 8 Re: Selective events
OK here is the sample. It selectively sends event to the clients. It does not have any comment :). So, if you have any question, please feel free to post it here. This code compiles and runs fine. You can improve the server method to invoke any delegate.
class Client
{
private int clientID = -1;
public Client(int clientID)
{
this.clientID = clientID;
}
public int ClientID
{
get { return clientID; }
set { clientID = value; }
}
public void MyTestEventHandler(object sender, TestEventArgs eventArgs)
{
System.Console.WriteLine("Client " + clientID.ToString() + " is called");
}
static void Main(string[] args)
{
// create server object
Server server = new Server();
// create client objects.
Client c1 = new Client(1);
Client c2 = new Client(2);
// clients adds event handler to the events they are interested in.
server.SelectiveEvent += new MyTestEvent(c1.MyTestEventHandler);
server.SelectiveEvent += new MyTestEvent(c2.MyTestEventHandler);
// call server method to selectively invoke the clients
server.InvokeClients(new int[] { 2 }, new TestEventArgs());
}
}
public class Server
{
public event MyTestEvent SelectiveEvent;
public void InvokeClients(int[] clientIDs, TestEventArgs args)
{
if ((clientIDs != null) && (clientIDs.Length > 0))
{
foreach (MyTestEvent eventDelegate in SelectiveEvent.GetInvocationList())
{
Client targetObject = eventDelegate.Target as Client;
// loop thro' the array and see whether the client is in the id list.
// there are better way to do it if you don't want to loop for every client.
// this will give you an idea.
for (int index = 0; index < clientIDs.Length; index++)
{
if (targetObject.ClientID == clientIDs[index])
{
eventDelegate(this, args);
break;
}
}
}
}
}
}
/// <summary>
/// TestEventArgs
/// </summary>
public class TestEventArgs : EventArgs
{
// Some Event args here.
}
/// <summary>
/// Delegate declaration
/// </summary>
public delegate void MyTestEvent(object sender, TestEventArgs eventArgs);
