After the first receiver exits, its channel is still saved in the receiverClients collection in the service, so the next time a transmit occurs, the server will attempt to callback to a non-existent client. You must remove the receiver from the collection when it ends, perhaps with an unsubscribe contract operation. There are a number of ways to implement this. Here is one example. (These are the changes, only - please let me know if you would like the entire project.)
In IContactManagerUserService.cs:
// receivers must identify themselves
[OperationContract(IsOneWay = true)]
void SubscribeAsReceiver(string receiverID);
// new operation
[OperationContract(IsOneWay = true)]
void UnSubscribeAsReceiver(string receiverID);
In ContactManagerUserService.cs
// replace synchronized collection with thread-safe dictionary
using System.Collections.Concurrent;
ConcurrentDictionary<string, IContactManagerCallBackService> receiverClients;
public ContactManagerUserService()
{
receiverClients = new ConcurrentDictionary<string, IContactManagerCallBackService>();
}
public void SubscribeAsReceiver(string receiverID)
{
IContactManagerCallBackService client = OperationContext.Current.GetCallbackChannel<IContactManagerCallBackService>();
receiverClients.TryAdd(receiverID, client);
}
public void UnSubscribeAsReceiver(string receiverID)
{
IContactManagerCallBackService client;
receiverClients.TryRemove(receiverID, out client);
}
public void TransmitUserData(UserInfo info)
{
foreach (IContactManagerCallBackService receiverClient in receiverClients.Values)
{
receiverClient.PublishUserData(info);
}
}
In ReceiverClient.Program.cs (don't forget to update ServiceReferences since the contract has changed):
// one way to uniquely identify this receiver
string rcvID = Guid.NewGuid().ToString();
// .... //
receivingClient.SubscribeAsReceiver(rcvID);
// .... //
Console.ReadLine();
// Important - this line must be executed, or service will again throw error.
// So when debugging, don't just close window, press enter to execute this line.
// In more robust setting, this would probably go in finally{} block, or in Dispose()
receivingClient.UnSubscribeAsReceiver(rcvID);
Debugging Tip You may want to have a version of the service you can run locally, so you can step into it and debug it. Also, I have found logging messages to the service log to be very helpful when you can't run the service locally.
You can search WCF Publisher/Subscriber for more info.