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

3

9

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

Bogle answered 31/3, 2009 at 21:5 Comment(0)
B
10

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);
        }
    }
Bogle answered 1/4, 2009 at 15:43 Comment(1)
Binding to each ip address individually is right thing to do because otherwise your server has security hole - imagine (unlikely) situation when other service binds itself to particular host ip address and the same port while your service is bound to ALL ip addresses. In this case imposter will get all connection requests from clients comming to this ip address.Harelda
W
2

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

Westernize answered 1/4, 2009 at 0:58 Comment(0)
P
2

Looks like i'm bit late :). But anyway - there is quite simple way to make Wcf listen all available network interfaces "net.tcp://0.0.0.0:8523/WCFTestService".

Primal answered 11/3, 2016 at 9:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.