Доброго времени суток всем.
Помогите решить проблему при помощи WCF. Есть сервис, на нем хранятся определенные объекты, через контракты к нему подключаются клиенты и меняют значения объектов. Как сделать так, чтобы при изменении объекта одним клиентом его новое значение появлялось у других подключенных клиентов? Сделать необходимо на WCF.
Здравствуйте, thistle, Вы писали:
T>Доброго времени суток всем.
T>Помогите решить проблему при помощи WCF. Есть сервис, на нем хранятся определенные объекты, через контракты к нему подключаются клиенты и меняют значения объектов. Как сделать так, чтобы при изменении объекта одним клиентом его новое значение появлялось у других подключенных клиентов? Сделать необходимо на WCF.
Сервис определяет контракт и callback-интерфейс для этого контракта.
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface IServer
{
...
}
В контракте делаем один из методов с именем Advise, Init или как угодно еще, помечаем его атрибутом [OperationContract(IsInitiating = true)] и метод, который клиент должен вызвать перед окончанием работы с сервисом.
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface IServer
{
[OperationContract(IsInitiating = true)]
void Advise();
[OperationContract(IsTerminating = true)]
void Unadvise();
}
Теперь, каждый клиент перед началом работы с твоим сервисом обязан вызвать метод Advise (иначе получит ошибку во время выполнения), в котором сервис сохраняет ссылку на callback-интерфейс подключенного клиента, а перед завершением работы должен вызвать метод Unadvise(), где сервис удалит ссылку на callback-интерфейс соответствующего клиента.
Вот псевдокод метода Advise():
//получаем callback-интефейс текущего контекста
ICallback callBackInterface = OperationContext.Current.GetCallbackChannel<IEquipment>();
//сохраняем этот интерфейс в локальное хранилище
...
//подписываемся на события закрытия канала, чтобы удалить ссылку на интерфейс в случае
//проблем со связью с этим клиентом
OperationContext.Current.Channel.Faulted += EquipmentChannelFaulted;
OperationContext.Current.Channel.Closed += EquipmentChannelClosed;
В методе Unadvise нужно также удалить ссылку на интерфейс, аналогично, как и при потере связи с клиентом.
Поскольку каждая сессия содержит уникальный идентификатор (строковое представление GUID-а), то самым простым способом реализации хранилища, является использование ассоциативного массива по идентификатору сессии.
Теперь в методе сервиса, который изменяет некоторые переменные состояния необходимо уведомить всех клиентов через callback-интерфейс.
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface IServer
{
[OperationContract]
void FooChanged();
}
[ServiceContract(CallbackContract = typeof(ICallback))]
public interface IServer
{
[OperationContract(IsInitiating = true)]
void Advise();
[OperationContract]
void ChangeFoo(...);
[OperationContract(IsTerminating = true)]
void Unadvise();
}
Осталось только на стороне клиента реализовать callback-интерфейс, данные о котором теперь будет публиковаться в метаданных службы.