31

I have the need to know my actual local IP address (i.e. not the loopback address) from a Windows 8 WinRT/Metro app. There are several reasons I need this. The simplest is that in the UI of the app I'd like to show some text like "Your local network IP address is: [IP queried from code]".

We also use the address for some additional network comms. Those comms are perfectly valid because it all works if I look at the IP address in the Control Panel, then hard-code it into the app. Asking the user in a dialog to go look at the address and manually enter it is something I really, really want to avoid.

I would think it wouldn't be a complex task to get the address programmatically, but my search engine and StackOverflow skills are coming up empty.

At this point I'm starting to consider doing a UDP broadcast/listen loop to hear my own request and extract the address from that, but that really seems like a hackey kludge. Is there an API somewhere in the new WinRT stuff that will get me there?

Note that I said "WinRT app. That means the typical mechanisms like Dns.GetHostEntry or NetworkInterface.GetAllInterfaces() aren't going to work.

Phil
  • 42,255
  • 9
  • 100
  • 100
ctacke
  • 66,480
  • 18
  • 94
  • 155
  • Windows is only aware of the interfaces, if somebody assigns a local network ip address to a network device, that is the address ( it is perfectly valid ). What exactly are you trying to do with the ip address? You are unlikely going to be able to do a UDP broadcast/listen on anything but the ip address the interface knows about which most often is a local network address not valid outside of said network. – Security Hound Apr 26 '12 at 18:58
  • Take a look at http://msdn.microsoft.com/en-us/library/windows/apps/hh454046(v=vs.85).aspx – Security Hound Apr 26 '12 at 19:03
  • @Ramhound: not sure what I should be looking at - and this documentation doesn't square with the behavior I see with the Consumer Preview and VS11 Beta. For example the docs show `NetworkIntrface.GetAllNetworkInterfaces()` should work, but it doesn't exist. – ctacke Apr 26 '12 at 21:32

2 Answers2

35

After much digging, I found the information you need using NetworkInformation and HostName.

NetworkInformation.GetInternetConnectionProfile retrieves the connection profile associated with the internet connection currently used by the local machine.

NetworkInformation.GetHostNames retrieves a list of host names. It's not obvious but this includes IPv4 and IPv6 addresses as strings.

Using this information we can get the IP address of the network adapter connected to the internet like this:

public string CurrentIPAddress()
{
    var icp = NetworkInformation.GetInternetConnectionProfile();

    if (icp != null && icp.NetworkAdapter != null)
    {
        var hostname =
            NetworkInformation.GetHostNames()
                .SingleOrDefault(
                    hn =>
                    hn.IPInformation != null && hn.IPInformation.NetworkAdapter != null
                    && hn.IPInformation.NetworkAdapter.NetworkAdapterId
                    == icp.NetworkAdapter.NetworkAdapterId);

        if (hostname != null)
        {
            // the ip address
            return hostname.CanonicalName;
        }
    }

    return string.Empty;
}

Note that HostName has properties CanonicalName, DisplayName and RawName, but they all seem to return the same string.

We can also get addresses for multiple adapters with code similar to this:

private IEnumerable<string> GetCurrentIpAddresses()
{
    var profiles = NetworkInformation.GetConnectionProfiles().ToList();

    // the Internet connection profile doesn't seem to be in the above list
    profiles.Add(NetworkInformation.GetInternetConnectionProfile());

    IEnumerable<HostName> hostnames =
        NetworkInformation.GetHostNames().Where(h => 
            h.IPInformation != null &&
            h.IPInformation.NetworkAdapter != null).ToList();

    return (from h in hostnames
            from p in profiles
            where h.IPInformation.NetworkAdapter.NetworkAdapterId ==
                  p.NetworkAdapter.NetworkAdapterId
            select string.Format("{0}, {1}", p.ProfileName, h.CanonicalName)).ToList();
}
Phil
  • 42,255
  • 9
  • 100
  • 100
  • 3
    A challenge, indeed. My team will soon need to support Windows 2003+ (including Windows 8). The pain being that something as simple as finding the current machine's IP address requires any 'digging' at all. – Joseph Yaduvanshi May 09 '12 at 13:19
  • Supporting iOS requires reading documentation. I'd prefer more developers start regularly reading documentation. – surfasb May 11 '12 at 03:11
  • 1
    `hn.NetworkAdapter` has been be replaced with ``hn.IPInformation.NetworkAdapter`` in the final version of the `Windows.Networking.Connectivity.NetworkInformation` class. The revised version of the `var hostname` line should look something like `var hostname = NetworkInformation.GetHostNames().SingleOrDefault(hn => hn.IPInformation != null && hn.IPInformation.NetworkAdapter != null && hn.IPInformation.NetworkAdapter.NetworkAdapterId == icp.NetworkAdapter.NetworkAdapterId);`. – Richard Cook Jan 06 '13 at 22:33
  • All I'm getting here is 10.0.0.1. I assume that's not correct, what should be done differently? @Phil – AndreasB Feb 17 '13 at 22:06
  • 1
    @AndrewB: I just tried both methods above and they work for me. 10.0.0.1 is a standard private IP address, like 192.168.x.x. Seems ok to me. – Phil Feb 17 '13 at 23:17
  • @Phil Ah, of course! For some reason I oversaw the fact that this was for local IP's, I was looking for external IP. Thanks. – AndreasB Feb 18 '13 at 10:04
  • 1
    I would recommand to add && hn.Type == HostNameType.Ipv4 in the query. Because I'll get an error if you have an IpV6 one too, like I have and an exception will be thrown because of SingleOrDefault. – Demian Flavius Jun 09 '13 at 21:47
  • NetworkInformation.GetInternetConnectionProfile() will return null if your device is connected to a network without internet connection (e.g. connected to a wlan router with an unplugged network cable). In this case your method CurrentIPAddress() would return an empty string instead of the IP address. – pr0gg3r Dec 21 '16 at 14:38
  • FYI, a device may have many connection profiles (one of my Windows Phones has over 20) using the same adapter. GetCurrentIpAddresses will return the same IP for all of them. Whenever you connect your device to a Wi-Fi, it creates a new connection profile and persists it. – Hong Feb 20 '17 at 19:24
  • How to distinguish a virtual network adapter from a physical network adapter? – Kiquenet Nov 27 '18 at 10:22
  • Query Local IP Address from ***remote computers*** in my intranet? I have several IPs – Kiquenet Nov 28 '18 at 08:21
1

About the accepted answer, you just need this:

HostName localHostName = NetworkInformation.GetHostNames().FirstOrDefault(h =>
                    h.IPInformation != null &&
                    h.IPInformation.NetworkAdapter != null);

You can get the local IP Address this way:

string ipAddress = localHostName.RawName; //XXX.XXX.XXX.XXX

Namespaces used:

using System.Linq;
using Windows.Networking;
using Windows.Networking.Connectivity;
Bruno Lemos
  • 8,847
  • 5
  • 40
  • 51
  • This answer is totally incorrect. It might work in a particular network configuration but try to add virtual machines into the system and virtual switches and the first returned host name might be the virtual switch IP which is totally unusable. – Alex Jun 21 '16 at 00:29