views:

29

answers:

1

First, let me explain a little bit about my setup. My server is setup as a Marshaled singleton object:

 RemotingServices.Marshal(lsServer, ServerObject.objectUri);

In order to have two-way communication from the server to the client, the client activates a ServerObject, then passes in its own ClientObject (which is also a MarshalByRefObject) the server uses the ClientObject to talk back to the client:

var lsClient = new ClientObject();

var lsServer = (ServerObject)Activator.GetObject(typeof(ServerObject), url);
lsServer.attach(lsClient);

When the attach method is called, the server takes the ClientObject and stores it in a List:

public void attach(ClientObject client) {
    clientList.Add(client);
}

The server can then call a method on the ClientObject called "SendMessage" to communicate to each client in its list:

foreach(var c in clientList) {
    c.SendMessage("Hello");
}

This works great until a client is encountered that has disconnected. In this case, an error is thrown about the client refusing the connection. I can catch the error, but the problem is I cannot remove the reference to the ClientObject from the server's List. The following re-throws the "connection refused" exception anytime a client has been disconnected:

clientList.Remove(badClient);

So a couple of questions:

1- Is there a way to detect the connection state of a client without having to catch an error?

2- When I do detect a client that has disconnected, why does the attempt to remove the object from the server's list appear to "communicate" with the client (thus causing the exception to be thrown again?)

EDIT

As Patrick pointed out below, doing a Remove from a list causes the List to iterate my objects and do a comparison on them (calling .Equals) - this is what caused my ClientObject to attempt to communicate again and thus throw the exception.

To resolve it, I instead changed the List to a dictionary keyed off a unique ID supplied by my Client at the time of attaching to the server. Then I used that unique ID to remove the client.

I never did find a direct way for determining if a client had disconnected other than catching the error.

A: 

Not sure on #2. However, if you're trying to remove an item from clientList from inside the foreach loop, you can't. That's a .NET rule -- no changing the contents of an enumerable object while it's being enumerated.

Instead, if you catch the error inside the foreach loop, store it in another list (a "disconnected" list). After the foreach, remove all of the disconnected items from the clientList.

Patrick Steele
Thanks, actually I'm not removing it from the list during a For loop. That error is something something about being unable to modify a collection. When I execute clientList.Remove(badClient), it's throwing a "Connection refused" exception... which seems strange, but it appears that by just referencing "badClient" it's attempting to use the object to communicate with the client.
Chu
What is clientList -- a List<T>? The Remove method first does an IndexOf to see if the object you passed in actually exists in the collection. Under the covers, IndexOf may call either the Equals operator of your object, or possibly GetHashCode(). Either of these calls would be sent over the wire -- and thus lead to the additional communication exception.
Patrick Steele
@Patrick - Yes, it's a List<ClientObject> - that makes sense then.
Chu