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