0

I've a system where I'm exchanging messages across different point to point comms channels- between Windows and embedded systems, and have done it all as pretty standard custom serialize/deserialize functions pretty much entirely done by hand, since that makes it easy to port between C# on the Windows side and C on the embedded.

Now I want to add a chunk that communicates between PCs on the net at large. Rather than do another batch of the same stuff, use TcpClient/TcpListener and keep track of overlapping messages and responses, I decided to have a look at WCF.

After looking at lots of messages on here, and docs etc elsewhere, I've come up with a very simple app that exchanges messages, with the server containing one function that takes and returns an interface instance, rather than a fixed class. Even though the example has only one kind of message- hence only one type is set using the KnownType and ServiceKnownType attributes, I picture there being a few tens of different types of messages that could be sent, and I want to be able to add them fairly easily as things evolve.

Although no errors are generated by the code, the object that's instantiated at the far end has none of the data that was sent. I've tried packet sniffing to see if I can confirm the data's actually going on the wire but I can't understand the wire protocol. So I don't know if the data's disappearing in the client on transmission or in the server. If I change the code to use instances of TestMessageType directly rather than using the interface, it works fine.

The solution's made of three projects; a "types" assembly and then client and server console apps that reference that assembly. The types assembly contains this code;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Runtime.Serialization;

namespace WCF_TCP_Sandpit
{

    public interface ITestInterface
    {
        Int64 I64Value {get; set;}
    }

    [ServiceContract]
    public interface IServer
    {
        [OperationContract]
        [ServiceKnownType(typeof(TestMessageType))]
        ITestInterface Test(ITestInterface msg);
    }

    [DataContract]
    [KnownType(typeof(TestMessageType))]
    public class TestMessageType : ITestInterface
    {
        Int64 _v1;

        public long I64Value
        {
            get { return _v1;  }
            set { _v1 = value; }
        }

        public static Type[] KnownTypes()
        {
            return new Type[] { typeof(TestMessageType) };   
        }
    }
}

The server code is

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using WCF_TCP_Sandpit;
using System.Runtime.Serialization;

namespace Server
{  
    class Program : IServer
    {
        static void Main(string[] args)
        {
            using (ServiceHost serviceHost = new ServiceHost(typeof(Program), new Uri("net.tcp://127.0.0.1:9000")))
            {
                serviceHost.Open();

                // The service can now be accessed.
                Console.WriteLine("The service is ready.");
                Console.WriteLine("Press <ENTER> to terminate service.");
                Console.WriteLine();
                Console.ReadLine();
            }

        }

        #region IServer Members

        public ITestInterface Test(ITestInterface msg)
        {
            ITestInterface reply = new TestMessageType();

            reply.I64Value = msg.I64Value * 2;
            return reply;
        }

        #endregion 
    }
}

and the client code is

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WCF_TCP_Sandpit;

using System.ServiceModel;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            ITestInterface m,r;
            int i = 0;
            ChannelFactory<WCF_TCP_Sandpit.IServer> srv
                = new ChannelFactory<WCF_TCP_Sandpit.IServer>
                (new NetTcpBinding(), "net.tcp://127.0.0.1:9000");

            WCF_TCP_Sandpit.IServer s;
            s = srv.CreateChannel();

            while (true)
            {
                m = new WCF_TCP_Sandpit.TestMessageType();
                m.I64Value = i++;

                r = s.Test(m);

                Console.WriteLine("Sent " + m.I64Value + "; received " + r.I64Value);
                System.Threading.Thread.Sleep(1000);
            }
        }
    }
}

Can anyone cast some light on what's going wrong?

Craig Graham
  • 1,161
  • 11
  • 35
  • when you inspected the packets (when it worked) did it use xml? i can't recall if wcf will use the xml serializer out of the box but it may do. (from further reading it appears the binary serializer is used ootb). Have you tried wrapping your ITestMessage into a `Message` class (ie make ITestMessage a property of said Message class) – wal Jul 18 '12 at 15:10

1 Answers1

0

Don't you need the DataMember attribute on your I64Value property?

Graham Clark
  • 12,886
  • 8
  • 50
  • 82
  • Evidently :) Probably I'd lost it while changing over to the interface and not twigged. Wal- it's pure binary. I couldn't even see any particular value incrementing. But then, since it wasn't serializing in the first place, I wouldn't have. Thanks for the help. – Craig Graham Jul 19 '12 at 08:00