Создание маршрутизатора WCF - Дуплексные маршрутизаторы
ОГЛАВЛЕНИЕ
Дуплексные маршрутизаторы
В коде на рис. 6 показан пример контракта дуплексного маршрутизатора для поддержки ситуации, когда сообщения между клиентом, маршрутизатором и службами приложений отправляются по протоколу TCP. У этого контракта следующие отличия от традиционного контракта маршрутизатора типа запрос-ответ.
- ProcessMessage теперь является односторонней операцией.
- Контракту службы требуются сеансы, и у него имеется соответствующий контракт обратного вызова. Важно обратить внимание на то, что при этом не требуется клиент для реализации обратного вызова; это внутренняя задача маршрутизатора.
- У контракта обратного вызова имеется единственный метод для получения ответов от обращений маршрутизатора к службам приложений. Обратите внимание, что службы не знают о том, что их ответы отправляются в канал обратного вызова; они могут быть сообщениями запрос-ответ.
Рис. 6 Контракт дуплексного маршрутизатора
[ServiceContract(Namespace =
"http://www.thatindigogirl.com/samples/2008/01",
SessionMode = SessionMode.Required,
CallbackContract = typeof(IDuplexRouterCallback))]
public interface IDuplexRouterService {
[OperationContract(IsOneWay=true, Action = "*")]
void ProcessMessage(Message requestMessage);
}
[ServiceContract(Namespace =
"http://www.thatindigogirl.com/samples/2008/01",
SessionMode = SessionMode.Allowed)]
public interface IDuplexRouterCallback {
[OperationContract(IsOneWay=true, Action = "*")]
void ProcessMessage(Message requestMessage);
}
Архитектура дуплексного маршрутизатора показана на рис. 7. Что касается клиента, отправляются запросы и ожидается синхронный ответ. Маршрутизатор получает запросы на одностороннюю операцию и сохраняет клиентский канал обратного вызова, чтобы отправить ответ. Тем временем маршрутизатор перенаправляет сообщения, используя дуплексный канал, и обеспечивает канал обратной связи для получения ответа от службы.
Рис. 7 Архитектура дуплексного маршрутизатора
Служба получает запрос и отправляет синхронный ответ, полученный посредством канала обратного вызова маршрутизатора. Этот канал обратного вызова в свою очередь использует клиентский канал обратного вызова для отправки ответа клиенту. От начала до конца операция выполняется синхронно, но маршрутизатор разъединяет действия и для коррелирования сообщений опирается на дуплексную связь в базовых каналах получения и отправки.
Реализация маршрутизатора для этого случая показана на рис. 8. Существует несколько соответствующих изменений в реализациях маршрутизатора типа запрос-ответ. Во-первых, маршрутизатор поддерживает сеансы и реализует дуплексный контракт. Когда маршрутизатор перенаправляет сообщения службам, дуплексный канал создается с помощью DuplexChannelFactory<T>, что означает предоставление объекта обратного вызова, который будет получать ответы от службы.
Рис. 8 Реализация дуплексного маршрутизатора
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
ConcurrencyMode = ConcurrencyMode.Multiple,
AddressFilterMode=AddressFilterMode.Any,
ValidateMustUnderstand=false)]
public class DuplexRouterService : IDuplexRouterService, IDisposable {
object m_duplexSessionLock = new object();
IDuplexRouterService m_duplexSession;
public void ProcessMessage(Message requestMessage) {
lock (this.m_duplexSessionLock) {
if (this.m_duplexSession == null) {
IDuplexRouterCallback callback =
OperationContext.Current.GetCallbackChannel
<IDuplexRouterCallback>();
DuplexChannelFactory<IDuplexRouterService> factory =
new DuplexChannelFactory<IDuplexRouterService>
(new InstanceContext(null,
new DuplexRouterCallback(callback)), "serviceEndpoint");
factory.Endpoint.Behaviors.Add(new MustUnderstandBehavior(false));
this.m_duplexSession = factory.CreateChannel();
}
}
this.m_duplexSession.ProcessMessage(requestMessage);
}
public void Dispose() {
if (this.m_duplexSession != null) {
try {
ICommunicationObject obj = this.m_duplexSession as
ICommunicationObject;
if (obj.State == CommunicationState.Faulted)
obj.Abort();
else
obj.Close();
}
catch {}
}
}
}
public class DuplexRouterCallback : IDuplexRouterCallback {
private IDuplexRouterCallback m_clientCallback;
public DuplexRouterCallback(IDuplexRouterCallback clientCallback) {
m_clientCallback = clientCallback;
}
public void ProcessMessage(Message requestMessage) {
this.m_clientCallback.ProcessMessage(requestMessage);
}
}
Объект обратного вызова реализует контракт обратного вызова, и он будет получать ответы от служб. Этот объект обратного вызова должен использовать клиентский канал обратного вызова для отправки ответа клиенту.
Экземпляр службы маршрутизатора, ссылка на клиентский канал обратного вызова и канал обратного вызова маршрутизатора существуют в течение сеанса связи с клиентом. По этой причине, чтобы все это работало, маршрутизатор должен предоставить конечные точки, поддерживающие сеансы, а подчиненная служба должна поддерживать сеансы.