Как определить (на стороне сервера), какой контракт использовал клиент WCF для подключения (несколько контрактов)?

Учтите следующее:

У меня есть один главный сервер и несколько серверов в разных местах, которые могут взаимодействовать с главным сервером. Дополнительно (GUI) клиенты могут подключаться к каждому серверу.

Итак, у меня есть публичный интерфейс, который известен всем:

[ServiceContract(SessionMode = SessionMode.Required)]
public interface IBaseService
{
    [OperationContract]
    void Subscribe();

    [OperationContract]
    void Unsubscribe();
}

Кроме того, серверы поддерживают контракт обратного вызова, так что главный сервер может инициировать запросы на подключенных к нему серверах.

[ServiceContract(CallbackContract = typeof(ICallback), SessionMode = SessionMode.Required)]
interface IServerService : IBaseService
{
}

public interface ICallback
{
    [OperationContract]
    [FaultContract(typeof(ExceptionDetail))]
    void TheCallback();
}

Это означает, что сервер имеет 2 реализованных контракта. Поэтому, когда я повторяю всех подписчиков (на Subscribe Я кеширую все OperationContext) на главном сервере и вызов контракта обратного вызова для клиентов это просто тайм-аут! Я ожидал какое-то несоответствие ContractMismatch. Что-нибудь (и немедленно!), Кроме времени ожидания операции?!?

Я также попытался выяснить имя контракта, который клиент использовал для подключения (OperationContext.Current). Но это также не было успешным. Это говорит IServerService в обоих случаях в OperationContext.Current.EndpointDispatcher.ContractName,

Есть ли возможность на стороне сервера выяснить, какие OperationContract использовался клиентом при подключении?

Конечно я мог бы расширить интерфейс сервера методом SubscribeServer но это кажется мне безобразным.

РЕДАКТИРОВАТЬ:

как и предполагалось, я реализовал MessageInspector, Но в AfterReceiveRequest IClientChannel может быть успешно приведен к ICallback

Что еще более странно, так это то, что стек вызовов уже содержит ReliableDuplexSessionChannel:

>   XYZ.exe!XYZ.AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext) Line 99  C#
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.AfterReceiveRequestCore(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x86 bytes 
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(ref System.ServiceModel.Dispatcher.MessageRpc rpc) + 0x37 bytes 
System.ServiceModel.dll!System.ServiceModel.Dispatcher.MessageRpc.Process(bool isOperationContextSet) + 0x151 bytes 
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(System.ServiceModel.Channels.RequestContext request, bool cleanThread, System.ServiceModel.OperationContext currentOperationContext) + 0x644 bytes 
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(System.ServiceModel.Channels.RequestContext request, System.ServiceModel.OperationContext currentOperationContext) + 0x1d2 bytes    
System.ServiceModel.dll!System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(System.IAsyncResult result) + 0x4b bytes 
System.Runtime.DurableInstancing.dll!System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult result) + 0x32 bytes  
System.Runtime.DurableInstancing.dll!System.Runtime.AsyncResult.Complete(bool completedSynchronously) + 0x16b bytes 
System.Runtime.DurableInstancing.dll!System.Runtime.InputQueue<System.ServiceModel.Channels.Message>.AsyncQueueReader.Set(System.Runtime.InputQueue<System.ServiceModel.Channels.Message>.Item item) + 0x41 bytes   
System.Runtime.DurableInstancing.dll!System.Runtime.InputQueue<System.ServiceModel.Channels.Message>.Dispatch() + 0x320 bytes   
System.ServiceModel.dll!System.ServiceModel.Channels.ReliableDuplexSessionChannel.ProcessDuplexMessage(System.ServiceModel.Channels.WsrmMessageInfo info) + 0x7cb bytes 
System.ServiceModel.dll!System.ServiceModel.Channels.ServerReliableDuplexSessionChannel.ProcessMessage(System.ServiceModel.Channels.WsrmMessageInfo info) + 0x2a7 bytes 
System.ServiceModel.dll!System.ServiceModel.Channels.ReliableDuplexSessionChannel.HandleReceiveComplete(System.IAsyncResult result) + 0x1fa bytes   
System.ServiceModel.dll!System.ServiceModel.Channels.ReliableDuplexSessionChannel.OnReceiveCompletedStatic(System.IAsyncResult result) + 0x86 bytes 
System.Runtime.DurableInstancing.dll!System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult result) + 0x32 bytes  
System.Runtime.DurableInstancing.dll!System.Runtime.AsyncResult.Complete(bool completedSynchronously) + 0x16b bytes 
System.ServiceModel.dll!System.ServiceModel.Channels.ReliableChannelBinder<System.__Canon>.InputAsyncResult<System.__Canon>.OnInputComplete(System.IAsyncResult result) + 0x7a bytes    
System.Runtime.DurableInstancing.dll!System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult result) + 0x32 bytes  
System.Runtime.DurableInstancing.dll!System.Runtime.AsyncResult.Complete(bool completedSynchronously) + 0x16b bytes 
System.ServiceModel.dll!System.ServiceModel.Channels.FramingDuplexSessionChannel.TryReceiveAsyncResult.OnReceive(System.IAsyncResult result) + 0xa9 bytes   
System.Runtime.DurableInstancing.dll!System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult result) + 0x32 bytes  
System.Runtime.DurableInstancing.dll!System.Runtime.AsyncResult.Complete(bool completedSynchronously) + 0x16b bytes 
System.ServiceModel.dll!System.ServiceModel.Channels.SynchronizedMessageSource.ReceiveAsyncResult.OnReceiveComplete(object state) + 0x82 bytes  
System.ServiceModel.dll!System.ServiceModel.Channels.SessionConnectionReader.OnAsyncReadComplete(object state) + 0x175 bytes    
System.Runtime.DurableInstancing.dll!System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(System.IAsyncResult result) + 0x32 bytes  
System.dll!System.Net.LazyAsyncResult.Complete(System.IntPtr userToken) + 0xc5 bytes    
System.dll!System.Net.Security.NegotiateStream.ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, System.Net.AsyncProtocolRequest asyncRequest) + 0x126 bytes    
System.dll!System.Net.Security.NegotiateStream.ReadCallback(System.Net.AsyncProtocolRequest asyncRequest) + 0xea bytes  
System.dll!System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(int bytes) + 0x32 bytes 
System.dll!System.Net.FixedSizeReader.ReadCallback(System.IAsyncResult transportResult) + 0x9c bytes    
System.Runtime.DurableInstancing.dll!System.Runtime.AsyncResult.Complete(bool completedSynchronously) + 0x16b bytes 
System.ServiceModel.dll!System.ServiceModel.Channels.ConnectionStream.ReadAsyncResult.OnAsyncReadComplete(object state) + 0xa2 bytes    
System.ServiceModel.dll!System.ServiceModel.Channels.SocketConnection.AsyncReadCallback(bool haveResult, int error, int bytesRead) + 0x19b bytes    
System.Runtime.DurableInstancing.dll!System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(uint error, uint bytesRead, System.Threading.NativeOverlapped* nativeOverlapped) + 0x40 bytes  
mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) + 0x96 bytes    
[Native to Managed Transition]  

Означает ли это, что мой класс обслуживания реализует IServerService в котором определен контракт обратного вызова, что все подключающиеся клиенты маршрутизируются через дуплексный прокси-сервер? Неважно, какой контракт используется (или выполняется) клиентом?

2 ответа

На стороне сервера другой объект, который содержит входящие данные сообщения, OperationContext.Current.Host,

Вы можете получить информацию о договорах. Вот некоторые доступные данные:

Имя интерфейса: OperationContext.Current.Host.ImplementedContracts.FirstOrDefault().Value.Name

Пространство имен интерфейса: OperationContext.Current.Host.ImplementedContracts.FirstOrDefault().Value.Namespace

Полное название типа контракта: OperationContext.Current.Host.ImplementedContracts.FirstOrDefault().Value.ContractType.FullName

Вы также можете использовать Reflection в OperationContext.Current.Host.Description.ServiceTypeэто тип.

Надеюсь это поможет.

Если существует 2 контракта, один из которых является дуплексным, а другой нет, можно проверить тип канала, чтобы узнать, является ли он типом интерфейса обратного вызова или нет:

' we want to support optional callbacks, so this just returns nothing if the callback isn't what we are looking for
If TypeOf OperationContext.Current?.Channel Is TDuplexClientCallback Then
    Return OperationContext.Current?.GetCallbackChannel(Of TDuplexClientCallback)
Else
    Return Nothing
End If
Другие вопросы по тегам