Как определить (на стороне сервера), какой контракт использовал клиент 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