可重入的 ConcurrencyMode

Reentrant 示例演示了对服务实现使用 ConcurrencyMode.Reentrant 的必要性和含义。 ConcurrencyMode.Reentrant 表示服务(或回调)在给定时间只处理一条消息(类似于 ConcurencyMode.Single)。 为了确保线程安全,Windows Communication Foundation (WCF) 锁定 InstanceContext 处理消息,以便无法处理其他消息。 在处于可重入模式的情况下,InstanceContext 将仅在服务进行传出调用之前解除锁定,从而允许后续调用(可按示例中的演示重入),并在下次进入服务时被锁定。 为了演示此行为,示例演示了客户端和服务如何使用双工协定相互发送消息。

定义的合同是一个双向合同,其中Ping方法由服务实现,回调方法Pong由客户端实现。 客户端用滴答计数调用服务的 Ping 方法,从而启动调用。 服务检查时钟周期计数是否不等于 0,然后在递减时钟周期计数时调用回调 Pong 方法。 这由示例中的以下代码完成。

public void Ping(int ticks)
{
     Console.WriteLine("Ping: Ticks = " + ticks);
     //Keep pinging back and forth till Ticks reaches 0.
     if (ticks != 0)
     {
         OperationContext.Current.GetCallbackChannel<IPingPongCallback>().Pong((ticks - 1));
     }
}

回调的 Pong 实现具有与 Ping 实现相同的逻辑。 也就是说,它会检查时钟周期计数是否不为零,然后在回调通道上调用 Ping 该方法(在本例中,它是用于发送原始 Ping 消息的通道),时钟周期计数递减 1。 当滴答计数达到 0 时,该方法返回,从而将所有回复解包回启动该调用的客户端进行的第一个调用。 回调实现中显示了此过程。

public void Pong(int ticks)
{
    Console.WriteLine("Pong: Ticks = " + ticks);
    if (ticks != 0)
    {
        //Retrieve the Callback  Channel (in this case the Channel which was used to send the
        //original message) and make an outgoing call until ticks reaches 0.
        IPingPong channel = OperationContext.Current.GetCallbackChannel<IPingPong>();
        channel.Ping((ticks - 1));
    }
}

PingPong两种方法都是请求/答复,这意味着第一次调用Ping会等待,直到调用CallbackChannel<T>.Pong()返回后才有返回结果。 在客户端上,在由 Pong 方法进行的下一个 Ping 调用返回前,该方法不会返回。 由于回调和服务在答复挂起请求之前,必须进行传出请求/答复调用,因此这两个实现必须使用 ConcurrencyMode.Reentrant 行为进行标记。

设置、生成和运行示例

  1. 确保已为 Windows Communication Foundation 示例 执行One-Time 安装过程。

  2. 若要生成解决方案的 C# 或 Visual Basic .NET 版本,请按照 生成 Windows Communication Foundation 示例中的说明进行操作。

  3. 若要在单台计算机或跨计算机配置中运行示例,请按照 运行 Windows Communication Foundation 示例中的说明进行操作。

演示

若要运行示例,请生成客户端和服务器项目。 然后打开两个命令窗口,并将目录更改为 <sample>\CS\Service\bin\debug 和 <sample>\CS\Client\bin\debug 目录。 然后键入 service.exe 以启动服务,再使用作为输入参数传递的初始滴答值调用 Client.exe。 显示了 10 次滴答的示例输出。

Prompt>Service.exe
ServiceHost Started. Press Enter to terminate service.
Ping: Ticks = 10
Ping: Ticks = 8
Ping: Ticks = 6
Ping: Ticks = 4
Ping: Ticks = 2
Ping: Ticks = 0

Prompt>Client.exe 10
Pong: Ticks = 9
Pong: Ticks = 7
Pong: Ticks = 5
Pong: Ticks = 3
Pong: Ticks = 1