Posts Tagged ‘.Net 3.5’

WCF: Net.Tcp Binding on all IP Addresses

April 1st, 2009

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);
    }
}