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

发布于 2024-09-12 11:39:49 字数 573 浏览 3 评论 0原文

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

如果我使用 netTcpBinding,它会起作用,但由于我需要流式通信,所以我必须使用自定义绑定。

一切正常,直到我打开防火墙。此时,直接调用(从防火墙后面出去)可以正常工作,但回调却不能(防火墙阻止它)。

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

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

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

My goal is to reach a WCF service behind a firewall with no incoming ports opened.
The solution I chose is to host a duplex WCF service on the public side, that has as callback the same contract that was used if no firewall was involved.

It worked if I used netTcpBinding but since I need streamed communication I had to use the custom binding.

Everything works fine until I raise up the firewall. At that point, the direct call (from behind the firewall out) works fine, but the callback does not (firewall stops it).

The question is WHY? Shoudn't they use the same channel as for the predefined netTcpBinding?

Here is my channels stack in app.config:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鹿港巷口少年归 2024-09-19 11:39:49

实际行为是正确的。您已经使用了compositeDuplex 绑定元素 - 复合词的含义正是您所得到的 - 两个单独的通道,每个通道用于一个方向。仅对于默认情况下不支持双工通信的传输通道才需要复合双工。 TCP 传输通道的情况并非如此 - 请查看备注。如果您不使用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>

Actual behavior is correct. You have used compositeDuplex binding element - the meaning of composite word is exactly what you get - two separate channels each working for one direction. Composite duplex is needed only for transport channel which doesn't support duplex communication by default. That is not the case for TCP transport channel - check remarks. If you don't use compositeDuplex it should work like you have expected. Also there is no need to define whole new custom binding to allow streamed transport. NetTcpBinding also has TransportMode property which can be specified in configuration.

EDIT:
I have prepared working example with Net.TCP duplex communication. It doesn't use streaming. You are right that streaming is not possible when duplex TCP communication is used. You can try to combine duplex communication with chunking channel or check WCF Xtensions (commercial product).

Shared contracts

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);
    }
}

Service and host

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();
            }
        }
    }
}

Service configuration

<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>

Callback and client

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();
            }
        }
    }
}

Client configration

<configuration>
  <system.serviceModel>
    <client>
      <endpoint name="IDuplexService_NetTcp" address="net.tcp://localhost:8800/NetTcpDuplexService" binding="netTcpBinding"
                contract="NetTcpDuplexContracts.IDuplexService" />
    </client>
  </system.serviceModel>
</configuration>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文