GeoLocation refers to identifying a real-world geographic location of a computer, device or website visitor. There are a many websites that provide this service, some are free and some are not. A populare and free one is hostip.info. It provides country, country code, country flag, city, latitude and longitude of an IP address.

This wrapper class is a modified version of the one Scott Hanselman posted in Geolocation/Geotargeting (Reverse IP Address Lookup) in ASP.NET MVC made easy. I modified the class to accept an input string containing an IP address or a domain name to get it's location, instead of returning the current visitor's. I add the GetCountryFlagURL function that takes an IP address or a domain name and returns the URL of the country's flag.

Hanselman's LocationInfo class contained the coordinates of the IP address. But I removed it, because the coordinate element in the XML data is only returned when there are coordinates in the database, and the LINQ statement throws an exception when the element is missing. The class and the sample projects work with ASP.NET and Windows Forms as well as Mono. The source code includes a Windows Forms project and an ASP.NET project to test the class.

public class LocationInfo
{
    public string CountryName { get; set; }
    public string CountryCode { get; set; }
    public string Name { get; set; }
}

public class GeoLocation
{
    private static Dictionary<string, LocationInfo> cachedIps = 
        new Dictionary<string, LocationInfo>();

    public static string GetCountryFlagURL(string domainName)
    {
        domainName = Dns.GetHostEntry(domainName).AddressList[0].ToString();
        return "http://api.hostip.info/flag.php?ip=" + domainName;
    }

    public static LocationInfo GetLocationInfo(string ipParam)
    {
        LocationInfo result = null;
        IPAddress i = Dns.GetHostEntry(ipParam).AddressList[0];
        string ip = i.ToString();

        if (!cachedIps.ContainsKey(ip))
        {
            string r;
            using (WebClient webClient = new WebClient())
            {
                r = webClient.DownloadString(
                    String.Format("http://api.hostip.info/?ip={0}&position=true", ip));
            }

            XDocument xmlResponse = XDocument.Parse(r);

            try
            {
                foreach (XElement element in xmlResponse.Root.Nodes())
                {
                    if (element.Name.LocalName == "featureMember")
                    {
                        //element Hostip is the first element in featureMember
                        XElement hostIpNode = (XElement)element.Nodes().First();

                        result = new LocationInfo();

                        //loop thru the elements in Hostip
                        foreach (XElement node in hostIpNode.Elements())
                        {
                            if (node.Name.LocalName == "name")
                                result.Name = node.Value;

                            if (node.Name.LocalName == "countryName")
                                result.CountryName = node.Value;

                            if (node.Name.LocalName == "countryAbbrev")
                                result.CountryCode = node.Value;
                        }
                    }
                }
            }
            catch (NullReferenceException)
            {
                //Looks like we didn't get what we expected.  
            }

            if (result != null)
            {
                cachedIps.Add(ip, result);
            }
        }
        else
        {
            result = cachedIps[ip];
        }
        return result;
    }
}