Search code examples
c#asp.netdockerasp.net-web-api

How to get IP and Port on which the server listening


I want to make an image of my ASP.NET Web API, which I will run in Docker with different ports, was saved at startup to an entry in the database with an IP and a Port on which to access it.

And then in my Back Office Web API, getting one such record from the database, for example, I could use the provider I wrote to access the same ASP.NET Web API using its IP and port.

Now when I am launching the Web API, I get the following entry in the database:

ip: 26.16.80.29
port: 53256

Although my Web API is listening:

Microsoft.Hosting.Lifetime: Information: Now listening on: https://localhost:5001
Microsoft.Hosting.Lifetime: Information: Now listening on: http://localhost:5000

Now I use the following method to get the IP and Port that I found on the Internet:

// Getting IP 
IPAddress[] ipAddresses = Dns.GetHostAddresses(Dns.GetHostName());
IPAddress ip = ipAddresses.Select(ip => ip)
                          .Where(ip => ip.AddressFamily == AddressFamily.InterNetwork)
                          .First();

// Getting port
var listener = new TcpListener(IPAddress.Any, 0);
listener.Start();
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();

I also have an idea to take this information from launchSettings.json:

"profiles": {
   "Docker": {
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}"
   }
}

But if I suddenly don't want to use the launch in the container, but want to use any other profile, everything should work the same way

What solutions can there be to this problem?


Solution

  • I don't know if this will work inside a Docker image, probably behind a NAT / Load Balancer / Etc. But I did use it with some success before:

    public static class NetworkingHelpers
    {
        /// <summary>
        /// Gets the preferred IP Address to the <paramref name="targetIp"/> by connecting with an UDP socket.
        /// Works well on Windows, Linux and Mac (source: https://stackoverflow.com/a/27376368/285678)
        /// </summary>
        /// <remarks>It won't work if there is no network connectivity. Since it finds the target's "preferred" 
        /// outboung IP Address the result can vary for different targets on machines with multiple network
        /// interfaces. It normally finds out the correct, preferred local IP (which is NOT your NAT IP!).</remarks>
        /// <returns></returns>
        public static IPAddress GetLocalIPv4Address(string? targetIp = null) {
            using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0);
            socket.Connect(targetIp ?? "8.8.8.8", 65530);
            IPEndPoint endPoint = (IPEndPoint)socket.LocalEndPoint;
            return endPoint.Address;
        }
    }
    

    It works "most" of the time :-) But, in production, I really do get the "external" IP address from a config file just to be sure, and only resort to this kind of "hack" if the configuration is missing.