#wcf #callback #wcf-callbacks
#wcf #обратный вызов #wcf-обратные вызовы
Вопрос:
У меня есть одна служба WCF, которая предоставляет две операции — IncrementList() и getList(). Клиент B подключается к службе, вызывает getList() и отображает пользователю. Клиент A имеет возможность обновлять этот список, вызывая IncrementList() .
Я хочу, чтобы клиент B получал уведомление при вызове IncrementList(), чтобы он мог снова вызвать getList() для отображения обновленных данных.
Не могли бы вы описать, как вы это реализуете? Обратные вызовы? Дуплекс? Издатель / Подписчик?
Что-нибудь новое в WCF 4.0, которое помогает в этом сценарии?
Спасибо!
Комментарии:
1. какую нагрузку вы ожидаете? существуют ли какие-либо прокси / брандмауэры и т. Д.? Насколько быстрым должно быть уведомление?
2. В чем вопрос? Ответ на ваш текущий вопрос просто да , потому что уведомления могут быть получены только с помощью дуплексной привязки, которая использует обратные вызовы, а дуплексная привязка является основой шаблона обмена сообщениями публикации / подписки. В WCF 4 больше ничего нет для поддержки этого.
3. Яхия, никаких прокси или брандмауэров, и уведомление не обязательно должно быть в режиме реального времени.
4. Ладислав Мрнка, извините — я понимаю, что мой вопрос довольно расплывчатый, и ясно, что я очень новичок в WCF … Мой вопрос действительно «как бы вы это реализовали?»
Ответ №1:
Что-то, что вы должны решить заранее, так это хотите ли вы отправлять весь список, когда он увеличивается (тяжелый), или только обновленный элемент для каждого клиента. Приведенный ниже код предназначен для отправки всего списка, но его легко изменить, просто чтобы отправить обновленный объект (рекомендуется).
При запуске приложения клиент 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)
Комментарии:
1. Ricibob, большое вам спасибо за такой полный ответ! Я, очевидно, новичок в WCF, и у меня вопрос: я думал, что я мог бы просто выставить событие из службы, и клиент подпишется на него. Затем обработчик события вызовет getList() . Возможно ли это? Я не прошу писать код для меня, но не могли бы вы описать шаги? 🙂 спасибо!!!
2. @GustavoCavalcanti Я довольно хорошо знаком с WCF, но приложение, основанное более или менее на вышеупомянутом, работает хорошо. Насколько я понимаю, вы не можете отображать событие непосредственно в интерфейсе сервера. Вместо этого я здесь предоставляю метод в интерфейсе обратного вызова с аналогичной сигнатурой для события, а затем на стороне клиента реализация этого метода запускает событие — просто передавая аргументы. Наше приложение пользовательского интерфейса работает с событиями в интерфейсе, но мы можем подключить локальную реализацию интерфейса (обычные события) или удаленную реализацию прокси-сервера wcf, которая работает с методом-> событие
3. Ricibob, не могли бы вы показать код для PushList? Спасибо!