Что-то, что вы должны решить заранее, это если вы хотите выдвинуть весь список при его увеличенном (тяжелом) или просто обновленный элемент для каждого клиента. Приведенный ниже код предназначен для отправки всего списка, но его легко изменить, просто чтобы обновить обновленный объект (рекомендуется).
При запуске приложения клиент B должен позвонить Register_client
, а затем GetList
. Впоследствии он будет уведомлен с помощью обратного вызова при увеличении списка (клиент должен включить этот интерфейс)
Для вызова GetList
требуется дуплексный канал и SessionMode.Required
.
Ваш сервер должен подразумевать:
[ServiceContract(SessionMode = SessionMode.Required
CallbackContract = typeof(IMyCallback))]
public interface IMyServer {
[OperationContract]
void Register_client();
[OperationContract(IsOneWay = true)]
void IncrementList();
[OperationContract]
ListObject[] GetList();
}
[DataContract]
public class ListObject {
[DataMember]...
}
Ваш клиент должен подразумевать:
public interface IMyCallback {
[OperationContract(IsOneWay = true)]
void PushList(ListObject[] list);
}
Зарегистрировать клиента просто нужно сохранить интерфейс обратного вызова клиента для использования при увеличении списка, например:
public override void Register_client() {
// Store callback interfaces for all connected clients:
IMyCallback callback = OperationContext.Current.GetCallbackChannel<IGatewayServerCallback>();
if (clients.Contains(callback) == false)
clients.Add(callback);
Trace.WriteLine(string.Format("Client connection established ({0})", clients.Count));
}
Где:
private List<IMyCallback> clients = new List<IMyCallback>();
Реализация IncrementList
должна сделать обратный вызов, чтобы отправить новый список (или, точнее, просто новый объект, который был добавлен в список) клиенту - что-то вроде:
for (int i = 0; i < clients.Count; i++) {
if (((ICommunicationObject)clients[i]).State == CommunicationState.Opened) {
try {
clients[i].PushList(list);
}
catch (Exception e) {
clients.RemoveAt(i--);
Trace.WriteLine(e);
Trace.WriteLine(string.Format("Removing client {0} (exception).", i + 1));
}
}
Имплиментация обратного вызова (на стороне клиента) выглядит примерно так:
public class MyCallback : IMyCallback {
public void PushList(ListObject[] list) {
// Were client side - update list code here...
}
Вероятно, для этой реализации обратного вызова требуется ссылка на некоторый объект, содержащий данные списка - возможно, это передается в конструктор (не показан).
Когда вы создаете экземпляр прокси-объекта, вам необходимо передать экземпляр обратного вызова в конструктор прокси - что-то вроде:
MyServerClient client_proxy = new MyServerClient(new InstanceContext(my_callback, binding_str)