双工系统WCF如何区分不同的通道实例?

use*_*291 9 wcf

嗯,我完全迷失了所以任何帮助都会受到赞赏

OperationContext.Current.InstanceContext是传入通道正在使用的当前服务实例的上下文.

在双工系统中,服务可以通过CallbackContract回调客户端.此CallbackContract非常类似于客户端上的服务,该服务正在侦听客户端已打开的通道上的服务的调用.此"客户端回调服务"只能通过其在服务上使用的相同通道进行访问,因此只有该服务才能访问它.

a)因此,在双工系统中,客户端也使用与客户端向服务发送消息的相同通道实例来接收来自服务的消息?

b)如果在请求 - 回复系统中客户端使用特定的通道实例clientChannel向服务发送消息,那么我假设同一实例(因此clientChannel)需要保持打开,直到服务向此实例发送回复,而在双工系统clientChannel需要时在会议结束前保持开放状态?

c)我假设这样的行为,因为据我所知,每个频道实例都有一个唯一的地址(或ID),这有助于区分它在同一客户端上运行的其他频道实例?当服务发回消息时,它还指定了该频道的ID?

因此,当双工系统客户端调用服务时,WCF(在客户端)创建clientChannel一个通过线路发送消息的通道实例.在服务器端,WCF创建通道实例serverChannel,该实例将消息传递给请求的操作(方法).当此方法想要通过回调到客户端时CallbackContract,它用于InstanceContext.GetCallBackChannel<>创建一个通道,其中包含调用服务的通道的ID(因此它包含确切的地址或ID clientChannel)?

d)双工系统客户端是否使用相同的通道实例来调用任何端点的操作?

谢谢

Din*_*esh 6

我不确定,但这是我对双工模式通信的理解.

我看了一下使用dotPeek反编译器在System.ServiceModel程序集中定义的InstanceContext类.

在内部有一个电话

this.channels = new ServiceChannelManager(this);
Run Code Online (Sandbox Code Playgroud)

这意味着,它正在使用传递相同InstanceContext实例的ServiceChannelManager创建通道.这样它就可以使用InstanceContext实例跟踪Channel.

然后在方法中绑定传入通道(服务到客户端)请求,实现方式如下:

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;
      }
    }
Run Code Online (Sandbox Code Playgroud)

所以回答你的疑问:

一个.是的,它在内部维护客户端和服务之间的呼叫的服务和InstanceContext(创建通道)关系.

湾 是的,通道需要保持打开状态,直到服务回复上下文,InstanceContext将负责关闭通道.

C.每个客户端都有唯一的会话ID,但服务中的InstanceContext类型取决于服务在合同实施时使用的InstanceContextMode.

d.它使用相同的频道.InstanceContext维护IncomingChannel和Outgoing channel的计数.传入信道是指向客户端的服务和传出客户端到服务的信道.您可以在VS中使用调试器查看此计数.

为了进一步说明,就双工服务的其他行为而言,以下是我们如何查看InstanceContext的行为以及如何创建通道实例:

我创建了一个Duplex服务演示:

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

该合同的实施方式如下:

[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>();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此实现中,请注意InstanceContextMode设置为PerCall的第一行.默认值为PerSession.

此枚举有三个选项:

  1. PerCall - 用于每个独立于Session的调用的InstanceContext的新实例

  2. PerSession - 用于每个会话的新实例

  3. Single - 用于所有客户端的InstanceContext的单个实例.

我创建了一个使用NetTcpBinding连接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);
Run Code Online (Sandbox Code Playgroud)

TCPCallbackHandler是Client中实现Callback合同的类,如下所示:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

为了查看InstanceContext的行为,我启动了服务,然后使用每个枚举操作启动了两个客户端,如上所述.结果如下:

1 - PerCall

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

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

这里 - urn:uuid:4c5f3d8b-9203-4f25-b09a-839089ecbe54是SessionId

由于每个客户端添加在客户端调用两次,并在PerCall - >的InstanceContext的新实例被创建每次调用,我们创建服务类的为每个客户端的两个呼叫一个新的实例.这里要注意的是,即使对于同一会话也会创建新实例

//首先调用合同的Add方法

client.Add(VAL1); - >创建了ServiceClass的新实例,值将增加到5

//第二次调用合同的Add方法

client.Add(val2次); - >创建了ServiceClass的新实例,值将增加到5

2 - PerSession

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

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

这里,ServiceClass的实例对于客户端是独立的,因为它们具有不同的会话运行.所以调用的增量是0 - > 5 - > 10(对于两个客户端分别)

3 - 单身

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

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

这里所有客户共享同一个ServiceClass实例,因此我们在第一个客户端中有0 - > 5 - > 10.第二个客户端将在同一个实例中递增,因此我们得到10 - > 15 - > 20.

根据调用,这将表现不同,并且可能会给出与客户端同时调用时相同的结果.

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

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

希望这可以帮助!