2

I am using WCF to transmit information between two identical copies of a program on separate computers, with the approach demonstrated on a single computer in the code below. I know that .NET 4.5 supports compression out of the box and I see an XML implementation in this question, but I don't understand how to enable it in this case. How can I modify the program below to use compression with the fewest/simplest changes?

// Reference to System.ServiceModel
class Program
{
    static void Main(string[] args)
    {
        var server = new DemoWcfServer();
        var handler = new DemoWcfHandler();

        Uri serviceUri = new Uri("net.tcp://localhost/SimpleWcfDemo");
        var binding = new NetTcpBinding();
        binding.MaxBufferSize = 100000000;
        binding.MaxReceivedMessageSize = 100000000;

        var host = new ServiceHost(server, serviceUri);
        host.AddServiceEndpoint(typeof(IDemoWcfServer), binding, "");
        host.Open();

        var cf = new DuplexChannelFactory<IDemoWcfServer>(handler, binding, new EndpointAddress(serviceUri));
        IDemoWcfServer serviceProxy = cf.CreateChannel();

        serviceProxy.DoStuff(BigString('T', 1000000));
        Console.ReadKey();
    }

    static string BigString(char c, int n)
    {
        var sb = new StringBuilder();
        for (int i = 0; i < n; i++)
            sb.Append(c);
        return sb.ToString();
    }

    [ServiceContract(CallbackContract = typeof(IDemoWcfCallback))]
    public interface IDemoWcfServer
    {
        [OperationContract]
        void DoStuff(string content);
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class DemoWcfServer : IDemoWcfServer
    {
        public void DoStuff(string content)
        {
            Console.WriteLine("Content of " + content.Length + " length received remotely; processing...");
            IDemoWcfCallback callback = OperationContext.Current.GetCallbackChannel<IDemoWcfCallback>();
            Task.Run(async () =>
            {
                await Task.Delay(TimeSpan.FromSeconds(3));
                callback.NotifyStuffComplete(BigString('R', 1000000));
            });
        }
    }

    public interface IDemoWcfCallback
    {
        [OperationContract]
        void NotifyStuffComplete(string content);
    }

    public class DemoWcfHandler : IDemoWcfCallback
    {
        public void NotifyStuffComplete(string content)
        {
            Console.WriteLine("Response of " + content.Length + " length received");
        }
    }
}
Community
  • 1
  • 1
Ben
  • 1,272
  • 13
  • 28

2 Answers2

3

To create the custom binding that includes compression (.NET 4.5+), replace this:

var binding = new NetTcpBinding();
binding.MaxBufferSize = 100000000;
binding.MaxReceivedMessageSize = 100000000;

with this:

var binding = new CustomBinding();
var be1 = new BinaryMessageEncodingBindingElement();
be1.CompressionFormat = CompressionFormat.GZip;
binding.Elements.Add(be1);
var be2 = new TcpTransportBindingElement();
be2.MaxBufferSize = 100000000;
be2.MaxReceivedMessageSize = 100000000;
binding.Elements.Add(be2);
binding = new CustomBinding(binding);

The desired behavior can be verified with Microsoft Message Analyzer (or Wireshark presumably) by listening on the local loopback to port 808. With compression, there are only 14 packets exchanged and none with a payload larger than 1200 bytes. Without compression, there are 238 packets with many larger than 64k.

Ben
  • 1,272
  • 13
  • 28
0

The answer in the question your quote solves it by using a custom binding. You could do this yourself as explained in this MSDN post.

Community
  • 1
  • 1
Wicher Visser
  • 1,513
  • 12
  • 21