双工WCF服务-直接呼叫和回调不使用同一通道

双工WCF服务-直接呼叫和回调不使用同一通道,wcf,stream,duplex,custom-binding,Wcf,Stream,Duplex,Custom Binding,我的目标是在防火墙后面实现WCF服务,而不打开传入端口。 我选择的解决方案是在公共端托管一个双工WCF服务,该服务具有与在不涉及防火墙的情况下使用的相同的契约 如果我使用netTcpBinding,它是有效的,但是因为我需要流式通信,所以我不得不使用自定义绑定 在我打开防火墙之前,一切正常。在这一点上,直接调用(从防火墙后面发出)可以正常工作,但回调不能正常工作(防火墙会阻止它) 问题是为什么?它们不应该使用与预定义netTcpBinding相同的通道吗 以下是app.config中的我的频道堆

我的目标是在防火墙后面实现WCF服务,而不打开传入端口。 我选择的解决方案是在公共端托管一个双工WCF服务,该服务具有与在不涉及防火墙的情况下使用的相同的契约

如果我使用netTcpBinding,它是有效的,但是因为我需要流式通信,所以我不得不使用自定义绑定

在我打开防火墙之前,一切正常。在这一点上,直接调用(从防火墙后面发出)可以正常工作,但回调不能正常工作(防火墙会阻止它)

问题是为什么?它们不应该使用与预定义netTcpBinding相同的通道吗

以下是app.config中的我的频道堆栈:

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

实际行为是正确的。您使用了CompositePlex绑定元素-CompositeWord的含义正是您得到的-两个单独的通道,每个通道为一个方向工作。复合双工仅用于传输通道,默认情况下不支持双工通信。这不是TCP传输通道检查的情况。如果您不使用CompositePlex,它应该像您预期的那样工作。此外,不需要定义全新的自定义绑定来允许流式传输。还具有可在配置中指定的TransportMode属性

编辑: 我已经准备了Net.TCP双工通信的工作示例。它不使用流媒体。您是对的,当使用双工TCP通信时,流是不可能的。您可以尝试将双工通信与分块通道或check(商业产品)相结合

共享合同

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();
            }
        }
    }
}
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();
            }
        }
    }
}
命名空间NetTcpDuplexService
{
公共类双工服务:IDuplexService
{
公共void操作(字符串消息)
{
Console.WriteLine(“DoAction:+消息”);
var callbackChannel=
OperationContext.Current.GetCallbackChannel();
callbackChannel.confirmation(“Ping back”+消息);
}
}
班级计划
{
公共静态void Main(字符串[]args)
{
尝试
{
使用(var-host=new-ServiceHost(typeof(DuplexService)))
{
host.Open();
Console.ReadLine();
}
}
捕获(例外e)
{
控制台写入线(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>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="IDuplexService_NetTcp" address="net.tcp://localhost:8800/NetTcpDuplexService" binding="netTcpBinding"
                contract="NetTcpDuplexContracts.IDuplexService" />
    </client>
  </system.serviceModel>
</configuration>

回调和客户端

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();
            }
        }
    }
}
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();
            }
        }
    }
}
命名空间NetTcpDuplexClient
{
公共类DuplexServiceCallback:IDuplexServiceCallback
{
公共无效确认(字符串消息)
{
控制台写入线(消息);
}
}
班级计划
{
公共静态void Main(字符串[]args)
{
DuplexChannelFactory=null;
尝试
{
var callbackService=新的DuplexServiceCallback();
var context=newinstancecontext(callbackService);
factory=新的DuplexChannelFactory(上下文,“IDuplexService_NetTcp”);
var channel=factory.CreateChannel();
channel.DoAction(“你好世界”);
工厂关闭();
Console.ReadLine();
}
捕获(例外e)
{
if(factory!=null&&factory.State!=CommunicationState.Closed)
{
factory.Abort();
}
控制台写入线(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>
<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="IDuplexService_NetTcp" address="net.tcp://localhost:8800/NetTcpDuplexService" binding="netTcpBinding"
                contract="NetTcpDuplexContracts.IDuplexService" />
    </client>
  </system.serviceModel>
</configuration>


在您提供的链接上,MSDN人员说,应该仅为不支持本地双工通信的传输协议指定元素,这意味着将创建两个通道,每个通信方向一个。另一方面,如果我没有在通道堆栈中指定节点,我就无法承载双工服务(我得到一个异常,说通道堆栈的双工通信配置不好)。因此,我不相信使用两个通道而不是一个通道的原因是因为我已经指定了。如果您可以提供在没有节点的情况下通过TCP传输进行双工通信的确切通道堆栈,这将证明您是100%正确的,您的帖子将是答案。如果几天内没有人提供任何其他信息,我会将您的帖子标记为答案。关于您帖子的最后一句话,NetCpBinding上的默认双工通信仅适用于缓冲传输模式。我添加了不使用复合通道的示例。我签入了procmon,但它没有打开到客户端的第二个连接。我找到了一个解决方法来实现我的目标。我没有将此作为答案发布,因为它实际上并不是我问题的答案。如果需要通过TCP进行双工流式通信,可以使用以下解决方案: