Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does in duplex system WCF differentiate between different channel instances?

Tags:

wcf

Uhm, I’m utterly lost so any help would be much appreciated

The OperationContext.Current.InstanceContext is the context of the current service instance that the incoming channel is using.

In a Duplex system, the service can callback to the client via a CallbackContract. This CallbackContract is much like a service on the client side that is listening for calls from the service on the channel that the client has opened. This “client callback service” can only be accessed via the same channel it used on the service and therefore only that service has access to it.

a) So in duplex systems the same channel instance with which client-side sends messages to the service, is also used by client to receive messages from the service?

b) If in request-reply system a client uses particular channel instance clientChannel to send a message to the service, then I assume this same instance ( thus clientChannel ) needs to stay opened until service sends back a reply to this instance, while in duplex system clientChannel needs to stay opened until the session is closed?

c) I’m assuming such behaviour since as far as I can tell each channel instance has a unique address ( or ID ) which helps to differentiate it from other channel instances ) running on the same client? And when service sends back a message, it also specifies an ID of this channel?

Thus when in Duplex system client calls a service, WCF creates ( on client side ) a channel instance clientChannel, which sends a message over the wire. On server’s side WCF creates channel instance serverChannel, which delivers the message to requested operation(method). When this method wants to callback to the client via CallbackContract, it uses InstanceContext.GetCallBackChannel<> to create a channel, which among other things contains the ID of the channel that called a service ( thus it contains an exact address or ID of clientChannel )?

d) Does in duplex systems client use the same channel instance to call any of endpoint’s operations?

Thank you

like image 283
user437291 Avatar asked Oct 27 '10 18:10

user437291


1 Answers

I am not sure but here is how I understand this for a Duplex mode communication.

I had a look at the InstanceContext class defined in the System.ServiceModel assembly using dotPeek decompiler.

Internally there is a call

this.channels = new ServiceChannelManager(this);

That means, it is creating channel using a ServiceChannelManager passing in the instance of the same InstanceContext. This way it keeping a track of the Channel with the instance of InstanceContext.

Then is binds Incoming channel (Service to Client) requests in method that is implemented as :

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;
      }
    }

So to answer your queries :

a. Yes, it internally maintains the Service and InstanceContext (which creates a channel) relations for calls between Client and Service.

b. Yes, the channel needs to stay opened untill the Service replies back to the context, in which the InstanceContext will take care of closing the channel.

c. Each client has a unique Session Id, but the InstanceContext type at the Service depends on the InstanceContextMode used at the Service on the implementation of the Contract.

d. It uses the same channel. InstanceContext maintains a count of IncomingChannel and Outgoing channel. Incoming channel are the one that are Service to Client directed and Outgoing are Client to Service directed. You can see this count using debugger in VS.

For the sake of further clarification, as far as the other behavior for a Duplex service is concerned, here is how we can look at the behavior of InstanceContext and how channel instance is created :

I created a Duplex service demo :

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IServiceDuplexCallback))]
public interface IServiceClass
{
    [OperationContract(IsOneWay = true)]
    void Add(int num1);
}

This contract is implemented as :

[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 this implementation notice the first line where InstanceContextMode is set to PerCall. The default is PerSession.

This enumeration has three options:

  1. PerCall - New instance of InstanceContext used for every call independent of Session

  2. PerSession - New instance used for every session

  3. Single - A single instance of InstanceContext used for all the clients.

I created a client which use NetTcpBinding to connect with 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 is the class in the Client that implements the Callback contract as:

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();
    }
}

To see the behavior of the InstanceContext, I started the service and then started two clients with each enumeration operation as discussed above. Here are the results :

1 - PerCall

Client 1 : urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5

Client 2 : urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 5 - urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 5

Here - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 is SessionId

Since for each client Add is called twice in the Client, and in PerCall -> new instance of InstanceContext is created every call, we create a new instance of ServiceClass for both the calls of every client. Point to note here is that new instance is created even for the same session

// First call to Add method of the Contract

client.Add(val1); -> New Instance of ServiceClass created and value will be incremented to 5

// Second call to Add method of the Contract

client.Add(val2); -> New Instance of ServiceClass created and value will be incremented to 5

2 - PerSession

Client 1 : urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 10

Client 2 : urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 5 - urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 10

Here the instance of ServiceClass is separate for both the client as they have different sessions running. So the increment in the calls is 0 -> 5 -> 10 (for both client separately)

3 - Single

Client 1 : urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 10

Client 2 : urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 15 - urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 20

Here the same instance of ServiceClass is shared by all clients so we have 0 -> 5 -> 10 in first client. The second client will increment in the same instance, so we get 10 -> 15 -> 20.

This will behave differently as per the call and may give result like when invoked at the same time from the clients.

Client 1 : urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 5 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54 15

Client 2 : urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 10 - urn:uuid:e101d2a7-ae41-4929-9789-6d43abf97f01 20

Hope this helps!

like image 68
Dinesh Avatar answered Sep 29 '22 18:09

Dinesh