2016-12-06 4 views
0

Considérez ce qui suit:Comment déterminer (du côté serveur) quel contrat un client WCF a utilisé pour se connecter (contrats multiples)?

J'ai un serveur maître et plusieurs serveurs sur des emplacements différents qui peuvent communiquer avec le serveur maître. Les clients supplémentaires (GUI) peuvent se connecter à chaque serveur.

J'ai donc une interface publique qui est connu par tout le monde:

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

    [OperationContract] 
    void Unsubscribe(); 
} 

De plus, les serveurs prennent en charge un contrat de rappel afin que le serveur maître peut déclencher des requêtes sur les serveurs connectés.

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

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

Signification que le serveur a 2 contrats mis en œuvre. Donc, lorsque je répète tous les abonnés (sur Subscribe je cache tout OperationContext) sur le serveur maître et que j'appelle le contrat de rappel pour les clients, il arrive juste à expiration! Je m'attendais à une sorte de ContractMismatch. Tout (et immédiatement!) Mais un délai d'attente d'opération?!?

J'ai également essayé de trouver le nom du contrat que le client a utilisé pour se connecter (OperationContext.Current). Mais ce n'était pas réussi non plus. Il dit IServerService dans les deux cas dans OperationContext.Current.EndpointDispatcher.ContractName.

Y a-t-il une possibilité côté serveur pour savoir quel OperationContract a été utilisé par le client lors de la connexion?

Bien sûr, je pourrais étendre l'interface du serveur par une méthode SubscribeServer mais cela me semble plutôt moche.

EDIT:

comme suggéré que je l'ai fait mettre en œuvre un MessageInspector. Mais dans le AfterReceiveRequest le IClientChannel peut être casté à ICallback

Ce qui est encore plus étrange est avec succès que la pile d'appel contient déjà 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] 

Est-ce que cela signifie si ma classe de service implémente l'IServerService qui a un rappel contrat défini, que tous les clients connectés sont acheminés via un proxy duplex? Quel que soit le contrat utilisé (ou implémenté) par le client?

Répondre

0

Côté serveur, un autre objet contenant des données de message entrant est OperationContext.Current.Host.

Vous pouvez obtenir des informations sur les contrats. Voici quelques données disponibles:

Nom de l'interface: OperationContext.Current.Host.ImplementedContracts.FirstOrDefault().Value.Name

espace de noms Interface: OperationContext.Current.Host.ImplementedContracts.FirstOrDefault().Value.Namespace

Nom du type de contrat complet: OperationContext.Current.Host.ImplementedContracts.FirstOrDefault().Value.ContractType.FullName

Vous pouvez également utiliser Reflection dans OperationContext.Current.Host.Description.ServiceType, c'est un type.

Espérons que cela aide.

+0

Le 'OperationContext.Current.Host' contient des informations sur le ServiceHost. Je suis intéressé par les informations sur le client. Le contrat utilisé par le client pour la création de chaîne. Dans le ImplmentedContracts sur le ServiceHost, je vois mon IServerService et mon IClientService. Mais aucune indication quel contrat a été utilisé par le client. – toATwork

+0

Vous devrez peut-être implémenter un inspecteur de messages. –

+0

Non, ça n'a pas bien marché. S'il vous plaît voir des informations supplémentaires dans la question. – toATwork