Duplex WCF service - Direct call and callback do not use same channel
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 netT开发者_开发问答cpBinding?
Here is my channels stack in app.config:
<customBinding>
<binding name="ReversedServiceBinding">
<compositeDuplex />
<oneWay />
<binaryMessageEncoding />
<tcpTransport transferMode="Streamed" />
</binding>
</customBinding>
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>
精彩评论