Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 887
Mel Green Avatar asked Mar 31 '09 21:03

Mel Green


2 Answers

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);
        }
    }
like image 127
Mel Green Avatar answered Sep 22 '22 21:09

Mel Green


Mel,

While I've never tried this before myself, here's some samples to look at that I've heard before. You may want to create your binding object first and then add the same instance to the AddServiceEndpoint method, just a thought so you're not creating new bindings every time as I remember reading somewhere that netTCPBindings should be a 1:1 relationship with the address (even though you're using different addresses).

I don't think you have to worry about port sharing as your opening up multiple ports.

Here's a sample of what you may want to accomplish with multiple ports.

http://www.aspfree.com/c/a/Windows-Scripting/WCF-and-Bindings/2/

Here's a good sample for using portsharing on the NetTcpBinding.

http://blogs.msdn.com/drnick/archive/2006/08/08/690333.aspx

-Bryan

like image 28
Bryan Corazza Avatar answered Sep 19 '22 21:09

Bryan Corazza