воскресенье, 21 апреля 2013 г.

"Контракту требуется свойство Duplex, однако..." (WCF)

Известно, что технология WCF (Windows Communication Foundation) поддерживает дуплексный режим общения сервера с клиентом. В таком случае не только клиент может обращаться к функциям сервера, но и сервер может вызывать функции на машине клиента. И если в обычном случае перед объявлением интерфейса контракта мы пишем аттрибут [Service Contract], то для дуплексного соединения нам необходимо написать что-то подобное:[ServiceContract(CallbackContract = typeof(IDuplexCallback))]
IDuplexCallback - это имя класса, обеспечивающего обратный вызов, его объявление аналогично объявлению других контрактов.
Однако, думаю, что у многих при попытке обновить Service Reference возникало сообщение вроде:
 "Контракту требуется свойство Duplex, однако привязка "BasicHttpBinding" его не поддерживает или этого не позволяет неправильная настройка."

Например, так:



Известно, что BasicHttpBinding не поддерживает дуплекс, нам нужен другой тип биндинга - wsDualHttpBinding. Открываем файл web.config (в проекте сервера - например, WCF Application и др.) Вот как он выглядит у меня:
Видимо, главное здесь - описать endpoint`ы.  Параметр binding имеет нужный нам тип - wsDualHttpBinding.
Вместо названия контракта (contract) duplexWCF.IDuplexService подставьте имя своего интерфейса-контракта, а вместо названия сервиса (service name) duplexWCF.DuplexService имя класса-реализации интерфейса-контракта (возможно, есть и другие варианты, но этот работает =) ). Endpoint MetaDataTcpEndpoint так же и оставляем - видимо, он нужен для получения каких-либо метаданных.
Обновляем Service Reference - работает =)

На сервере доступ к классу реализации функций обратной связи можно следующим способом:
OperationContext.Current.GetCallbackChannel();
IDuplexCallback - интерфейс класса обратной связи.
Возникает вопрос - а если клиентов несколько?  В таком случае эта функция при вызове серверной функции будет возвращать экземпляр класса того клиента, который производит вызов серверной функции. Нам остается только их хранить, например, в списке.

Теперь о клиентской реализации. Просто так объявить экземпляр сервиса-контракта не получится - ему нужно будет передать ссылку на нашу реализацию класса обратной связи.
Так что наследуемся от интерфейса и пишем нечто вроде:



Вот и всё)
Возможно, кому-нибудь поможет.

1 комментарий: