双工WCF服务 - 直接呼叫和回叫不使用相同的信道

时间:2010-07-29 13:55:21

标签: wcf stream duplex custom-binding

我的目标是在没有打开传入端口的防火墙后到达WCF服务。 我选择的解决方案是在公共端托管一个双工WCF服务,它具有与没有涉及防火墙时使用的相同合同作为回调。

如果我使用netTcpBinding,但是因为我需要流式通信,所以我必须使用自定义绑定。

在我启动防火墙之前,一切正常。此时,直接调用(从防火墙后面出来)工作正常,但回调没有(防火墙阻止它)。

问题是为什么?他们不会使用与预定义的netTcpBinding相同的频道吗?

这是我在app.config中的频道堆栈:

<customBinding>
  <binding name="ReversedServiceBinding">
    <compositeDuplex />
    <oneWay />
    <binaryMessageEncoding />
    <tcpTransport transferMode="Streamed" />
  </binding>
</customBinding>

1 个答案:

答案 0 :(得分:2)

实际行为是正确的。您已经使用了compositeDuplex绑定元素 - 复合词的含义正是您所获得的 - 两个独立的通道,每个通道都用于一个方向。仅对于默认情况下不支持双工通信的传输信道,仅需要复合双工。 TCP传输通道不是这种情况 - 检查remarks。如果你不使用compositeDuplex,它应该像你期望的那样工作。此外,无需定义全新的自定义绑定以允许流式传输。 NetTcpBinding还具有TransportMode属性,可以在配置中指定。

修改 我已经准备好了Net.TCP双工通信的工作实例。它不使用流媒体。您使用双工TCP通信时无法进行流式传输。您可以尝试将双工通信与分块通道结合使用,或选中WCF Xtensions(商业产品)。

共享合同

namespace NetTcpDuplexContracts
{
    [ServiceContract(SessionMode = SessionMode.Required, 
        CallbackContract = typeof(IDuplexServiceCallback))]
    public interface IDuplexService
    {
        [OperationContract(IsOneWay = true)]
        void DoAction(string message);
    }

    public interface IDuplexServiceCallback
    {
        [OperationContract(IsOneWay = true)]
        void ConfirmAction(string message);
    }
}

服务和主持人

namespace NetTcpDuplexService
{
    public class DuplexService : IDuplexService
    {
        public void DoAction(string message)
        {
            Console.WriteLine("DoAction: " + message);

            var callbackChannel = 
                OperationContext.Current.GetCallbackChannel<IDuplexServiceCallback>();
            callbackChannel.ConfirmAction("Ping back " + message);
        }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            try
            {
                using (var host = new ServiceHost(typeof(DuplexService)))
                {
                    host.Open();

                    Console.ReadLine();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.ReadLine();
            }
        }
    }
}

服务配置

<configuration>
  <system.serviceModel>
    <services>
      <service name="NetTcpDuplexService.DuplexService">
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8800/NetTcpDuplexService"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="netTcpBinding" contract="NetTcpDuplexContracts.IDuplexService" />
      </service> 
    </services>
  </system.serviceModel>
</configuration>

回调和客户

namespace NetTcpDuplexClient
{
    public class DuplexServiceCallback : IDuplexServiceCallback
    {
        public void ConfirmAction(string message)
        {
            Console.WriteLine(message);
        }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            DuplexChannelFactory<IDuplexService> factory = null;

            try
            {
                var callbackService = new DuplexServiceCallback();
                var context = new InstanceContext(callbackService);

                factory = new DuplexChannelFactory<IDuplexService>(context, "IDuplexService_NetTcp");
                var channel = factory.CreateChannel();
                channel.DoAction("Hello world");

                factory.Close();
                Console.ReadLine();
            }
            catch (Exception e)
            {
                if (factory != null && factory.State != CommunicationState.Closed)
                {
                    factory.Abort();
                }

                Console.WriteLine(e.Message);
                Console.ReadLine();
            }
        }
    }
}

客户端配置

<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="IDuplexService_NetTcp" address="net.tcp://localhost:8800/NetTcpDuplexService" binding="netTcpBinding"
                contract="NetTcpDuplexContracts.IDuplexService" />
    </client>
  </system.serviceModel>
</configuration>