Non sono sicuro, ma ecco come ho capito questo per una comunicazione in modalità duplex.
Ho dato un'occhiata alla classe InstanceContext definita nell'assembly System.ServiceModel usando decompiler dotPeek.
Internamente c'è una chiamata
this.channels = new ServiceChannelManager(this);
Ciò significa, sta generando canale utilizzando un ServiceChannelManager passando l'istanza dello stesso InstanceContext. In questo modo mantiene una traccia del Canale con l'istanza di InstanceContext.
Poi si lega è il canale in entrata (servizio a cliente) le richieste di metodo che viene implementato come:
internal void BindIncomingChannel(ServiceChannel channel)
{
this.ThrowIfDisposed();
channel.InstanceContext = this;
IChannel channel1 = (IChannel) channel.Proxy;
this.channels.AddIncomingChannel(channel1);
if (channel1 == null)
return;
switch (channel.State)
{
case CommunicationState.Closing:
case CommunicationState.Closed:
case CommunicationState.Faulted:
this.channels.RemoveChannel(channel1);
break;
}
}
Quindi, per rispondere alle vostre domande:
a. Sì, mantiene internamente le relazioni Servizio e InstanceContext (che crea un canale) per le chiamate tra Client e Servizio.
b. Sì, il canale deve rimanere aperto fino a quando il Servizio non risponde al contesto, in cui l'InstanceContext si occuperà della chiusura del canale.
c. Ogni client ha un ID sessione univoco, ma il tipo InstanceContext nel servizio dipende da InstanceContextMode utilizzato nel servizio per l'implementazione del contratto.
d. Usa lo stesso canale. InstanceContext mantiene il conteggio dei canali IncomingChannel e Outgoing. I canali in entrata sono quelli che sono diretti al cliente dal servizio al cliente e quelli in uscita sono diretti al cliente. Puoi vedere questo conteggio usando debugger in VS.
Per motivi di ulteriori chiarimenti, per quanto riguarda l'altro comportamento per un servizio duplex è interessato, ecco come possiamo osservare il comportamento di InstanceContext e come canale di istanza viene creata:
ho creato un duplex servizio di demo:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IServiceDuplexCallback))]
public interface IServiceClass
{
[OperationContract(IsOneWay = true)]
void Add(int num1);
}
il presente contratto è implementato come:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ServiceClass : IServiceClass
{
int result = 0;
public void Add(int num1)
{
result += num1;
callBack.Calculate(result);
}
IServiceDuplexCallback callBack
{
get
{
return OperationContext.Current.GetCallbackChannel<IServiceDuplexCallback>();
}
}
}
In questa implementazione notare la prima linea dove InstanceConte xtMode è impostato su PerCall. L'impostazione predefinita è PerSession.
Questa enumerazione ha tre opzioni:
PerCall - Nuova istanza di InstanceContext utilizzato per ogni chiamata indipendente sessione
PerSession - Nuova istanza utilizzata per ogni sessione
singolo - Una singola istanza di InstanceContext utilizzata per tutti i client.
ho creato un client che utilizzano NetTcpBinding di connettersi con Service:
InstanceContext ic = new InstanceContext(new TCPCallbackHandler(ref textBox1));
TCP.ServiceClassClient client = new TCP.ServiceClassClient(ic);
// First call to Add method of the Contract
client.Add(val1);
// Second call to Add method of the Contract
client.Add(val2);
TCPCallbackHandler è la classe nel client che implementa il contratto di richiamata come:
public class TCPCallbackHandler : TCP.IServiceClassCallback
{
TextBox t;
public TCPCallbackHandler(ref TextBox t1)
{
t = t1;
}
public void Calculate(int result)
{
t.Text += OperationContext.Current.SessionId + " " + result.ToString();
}
}
Per vedere la comportamento di InstanceContext, ho avviato il servizio e quindi ho avviato due client con ciascuna operazione di enumerazione come discusso sopra.Ecco i risultati:
1 - PerCall
client 1: urn: uuid: 4c5f3d8b-9203-4f25-b09a-839089ecbe54 - urn: uuid: 4c5f3d8b-9203-4f25-b09a- 839089ecbe54
client 2: urn: uuid: e101d2a7-ae41-4929-9789-6d43abf97f01 - urn: uuid: e101d2a7-ae41-4929-9789-6d43abf97f01
qui - urn: uuid: 4c5f3d8b-9203-4f25-b09a-839089ecbe54 è SessionId
Dato che per ogni cliente aggiungere è chiamato due volte nel client, e in PerCall -> nuova istanza di InstanceContext viene creato ogni chiamata , creiamo una nuova istanza di ServiceClass per entrambe le chiamate di ogni client. Punto da notare qui è che la nuova istanza viene creato anche per la stessa sessione
// prima chiamata al metodo Add del Contratto
client.Add (val1); -> nuova istanza di ServiceClass creato e il valore viene incrementato di 5
// Seconda chiamata per aggiungere il metodo del contratto
client.Add (val2); -> nuova istanza di ServiceClass creato e il valore viene incrementato di 5
2 - PerSession
client 1: urn: uuid: 4c5f3d8b-9203-4f25-b09a-839089ecbe54 - urna : uuid: 4c5f3d8b-9203-4f25-b09a-839089ecbe54
client 2: urn: uuid: e101d2a7-ae41-4929-9789-6d43abf97f01 - urn: uuid: e101d2a7-ae41-4929-9789 -6d43abf97f01
Qui l'istanza di ServiceClass è separata per entrambi il client poiché hanno sessioni diverse in esecuzione. Quindi, l'incremento delle chiamate è 0 -> 5 -> 10 (sia per il cliente separatamente)
3 - Single
client 1: urn: uuid: 4c5f3d8b-9203-4f25-b09a-839089ecbe54 - urn: uuid: 4c5f3d8b-9203-4f25-b09a-839089ecbe54
client 2: urn: uuid: e101d2a7-ae41-4929-9789-6d43abf97f01 - urn: uuid: e101d2a7- ae41-4929-9789-6d43abf97f01
Qui la stessa istanza di ServiceClass è condivisa da tutti i client, quindi abbiamo 0 -> 5 -> 10 nel primo client. Il secondo client incrementerà nella stessa istanza, quindi otteniamo 10 -> 15 -> 20.
Questo si comporta in modo diverso a seconda della chiamata e può dare risultati come quando invocato allo stesso tempo dai client.
client 1: urn: uuid: 4c5f3d8b-9203-4f25-b09a-839089ecbe54 - urn: uuid: 4c5f3d8b-9203-4f25-b09a-839089ecbe54
client 2: urn: uuid : e101d2a7-ae41-4929-9789-6d43abf97f01 - urn: uuid: e101d2a7-ae41-4929-9789-6d43abf97f01
Spero che questo aiuti!
Ho letto qualcosa che chiarisce un po ', ma lascia ancora delle risposte sul voodoo dei doppi collegamenti: i protocolli di trasporto TCP e Named Pipes supportano implicitamente i callback. Possono sempre tornare dal cliente. Per HTTP, DuplexClientBase gestisce la creazione dell'endpoint client ospitando un servizio sul client e ascoltando un indirizzo http temporaneo sulla porta 80 per i messaggi dal servizio. –
Trevor