WCF: Net.TCP multiple bindings, same port, different IP Addresses

Mel Green picture Mel Green · Mar 31, 2009 · Viewed 18.3k times · Source

I've run into a problem. I'm a little new at WCF so any help would be greatly appreaciated.

Here's my code:

public static void StartHosts()
    {
        try
        {
            // Create a new host
            ServiceHost host = new ServiceHost(typeof(ServerTasks));

            List<IPAddress> ips = new List<IPAddress>(Dns.GetHostAddresses(Dns.GetHostName()));
            if (IPAddress.Loopback != null)
                ips.Add(IPAddress.Loopback);

            ips.RemoveAll(i => i.AddressFamily != AddressFamily.InterNetwork);

            foreach (var ip in ips)
            {
                string uri = string.Empty;

                // Formulate the uri for this host
                uri = string.Format(
                    "net.tcp://{0}:{1}/ServerTasks",
                    ip.ToString(),
                    ServerSettings.Instance.TCPListeningPort
                );


                // Add the endpoint binding
                host.AddServiceEndpoint(
                    typeof(ServerTasks),
                    new NetTcpBinding(SecurityMode.Transport) { TransferMode = TransferMode.Streamed },
                    uri
                );

            }



            // Add the meta data publishing
            var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
            if (smb == null)
                smb = new ServiceMetadataBehavior();

            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            host.Description.Behaviors.Add(smb);

            host.AddServiceEndpoint(
                ServiceMetadataBehavior.MexContractName,
                MetadataExchangeBindings.CreateMexTcpBinding(),
                "net.tcp://localhost/ServerTasks/mex"
            );

            // Run the host
            host.Open();
        }
        catch (Exception exc)
        {
            DebugLogger.WriteException(exc);
        }
    }

An exception is thrown on the line: 'host.Open();'

The exception is:

System.InvalidOperationException A registration already exists for URI 'net.tcp://192.168.1.45:4329/ServerTasks'.

What I'm trying to do is bind to all the network addresses on the machine so that the client applications can reach the service from whatever network they see it on. When I run this code it finds and attempts to set up a binding for about 5 different IPs, including 127.0.0.1.

192.168.1.45 is the second IP that it attempts to bind to. At the point that it throws the exception I can see (using netstat) that the program has bound to the first IP in the list on port 4329. There isn't anything bound to port 4329 on the address mentioned in the exception.

Sorry there's not a lot of details, I wanted to give a concise post. If anyone needs any more info I'll be happy to supply it.

Note: I've tried setting PortSharingEnabled to true for the NetTcpBinding that gets created inside the foreach loop, but I still experienced the same error.

Any help or advise would be greatly appreaciated!

Thanks

Answer

Mel Green picture Mel Green · Apr 1, 2009

Thanks for the info Corazza!

I've figured out how to accomplish this. I was going about this all the wrong way.

My ultimate goal was to have the service listening on every IP Address available on the machine. Trying to bind to each address individually is the wrong way of doing this.

Instead, I only needed to bind the service to the machine's Host Name (not 'localhost') and WCF automatically listens on all adapters.

Here's the corrected code:

public static void StartHosts()
    {
        try
        {
            // Formulate the uri for this host
            string uri = string.Format(
                "net.tcp://{0}:{1}/ServerTasks",
                Dns.GetHostName(),
                ServerSettings.Instance.TCPListeningPort
            );

            // Create a new host
            ServiceHost host = new ServiceHost(typeof(ServerTasks), new Uri(uri));

            // Add the endpoint binding
            host.AddServiceEndpoint(
                typeof(ServerTasks),
                new NetTcpBinding(SecurityMode.Transport) 
                        { 
                            TransferMode = TransferMode.Streamed
                        },
                uri
            );

            // Add the meta data publishing
            var smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
            if (smb == null)
                smb = new ServiceMetadataBehavior();

            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            host.Description.Behaviors.Add(smb);

            host.AddServiceEndpoint(
                ServiceMetadataBehavior.MexContractName,
                MetadataExchangeBindings.CreateMexTcpBinding(),
                "net.tcp://localhost/ServerTasks/mex"
            );

            // Run the host
            host.Open();
        }
        catch (Exception exc)
        {
            DebugLogger.WriteException(exc);
        }
    }