WCF: Net.Tcp Binding on all IP Addresses

April 1st, 2009 by Mel Leave a reply »

In my new adventures in WCF I’ve come across this need to have the Service Host listening on all available IP Addresses on the server. I fumbled around with this for about a day before discovering the answer, which is really quite simple.

My first attempt at doing this was to create the Service Host and add a new binding for each available address, all bindings listening on the same port. This caused an exception to be thrown whenever the Service Host attempted to bind to the second address.

 So here’s the incorrect 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);
    }
}

What I didn’t realize is that all I needed to do was tell the Service Host to bind to the IP of 0 or 0.0.0.0 (thanks to seakingii and Chris for pointing this out below) and WCF would automatically bind to all addresses on the machine (unless you tell it not to). This was such a wonderful and amazing discovery that I just had to share it online!

 Here’s the correct code:

public static void StartHosts()
{
    try
    {
        // Formulate the uri for this host
        string uri = string.Format(
            "net.tcp://0:{1}/ServerTasks",
            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);
    }
}
Advertisement

13 comments

  1. Sparksy says:

    Think this will only listen on All IPv4 addresses, so technically its not all IP address, (I could be wrong).

    • Sparksy says:

      maybe this will work for all IPv6 addresses? have not tried it.

      string uri = string.Format(
      “net.tcp://[::0]:{0}/ServerTasks”,
      ServerSettings.Instance.TCPListeningPort
      );

  2. FoTeL says:

    great, but is a big problem with 0.0.0.0 address. I use WCF Disacovery and client receives 0.0.0.0 address.

  3. Leonard Lee says:

    Thanks for that! 🙂 Good tip!

  4. seakingii says:
    // Formulate the uri for this host
            string uri = string.Format(
                "net.tcp://0:{0}/ServerTasks",            
                ServerSettings.Instance.TCPListeningPort
            );
    
    • Mel says:

      Is there a comment or question in there somewhere?

      • Chris says:

        Having just googled this exact same problem, and wanting to help if any other WCF newbies like myself find your blog (which was the first hit on google)
        I belive seakingii is giving you the correct answer.
         
        Binding to net.tcp://0.0.0.0 or net.tcp:0 will bind to all IPs on the system.

  5. ZeroSkyX says:

    Thank you mate, that simple hint of yours really helped!

Leave a Reply