我不确定,但这是我对双工模式通信的理解。
我使用 dotPeek 反编译器查看了 System.ServiceModel 程序集中定义的 InstanceContext 类。
内部有调用
this.channels = new ServiceChannelManager(this);
这意味着,它使用 ServiceChannelManager 来创建通道,该 ServiceChannelManager 传入相同的 InstanceContext 的实例。
这样它就可以通过 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;
}
}
所以回答你的问题:
一个。是的,它在内部维护 Service 和 InstanceContext (创建通道)关系
Client 和 Service 之间的调用。
b.是的,通道需要保持打开状态,直到服务回复上下文,其中 InstanceContext
将负责关闭频道。
c。每个客户端都有唯一的 Session Id,但 Service 处的 InstanceContext 类型取决于 InstanceContextMode
在服务中用于执行合同。
d。它使用相同的通道。 InstanceContext 维护 IncomingChannel 和 Outgoing 通道的计数。
传入通道是面向客户的服务,而传出是面向客户的服务。
您可以在 VS 中使用调试器查看此计数。
为了进一步说明,就 Duplex 服务的其他行为而言,以下是我们如何看待 InstanceContext 的行为以及如何创建通道实例:
我创建了一个 Duplex 服务演示:
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IServiceDuplexCallback))]
public interface IServiceClass
{
[OperationContract(IsOneWay = true)]
void Add(int num1);
}
本合同执行为:
[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>();
}
}
}
在此实现中,请注意将 InstanceContextMode 设置为 PerCall 的第一行。 默认为 PerSession。
这个枚举有三个选项:
PerCall - InstanceContext 的新实例用于独立于 Session 的每个调用
PerSession - 用于每个会话的新实例
Single - InstanceContext 的单个实例用于所有客户端。
我创建了一个使用 NetTcpBinding 连接服务的客户端:
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是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();
}
}
为了查看 InstanceContext 的行为,我启动了服务,然后启动了两个客户端
如上所述的每个枚举操作。结果如下:
1 - 每次调用
客户端 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
由于每个客户端 Add 在客户端中调用两次,并且在 PerCall -> 每次调用都会创建 InstanceContext 的新实例,因此我们为每个客户端的调用创建一个新的 ServiceClass 实例。这里要注意的是,即使是同一个会话也会创建新实例
//第一次调用Contract的Add方法
client.Add(val1); -> 创建新的 ServiceClass 实例,值将增加到 5
// 第二次调用 Contract 的 Add 方法
client.Add(val2); -> 创建新的 ServiceClass 实例,值将增加到 5
2 - 每会话
客户端 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
希望这会有所帮助!