MVC/WebApi Getting location by IP Address

I am currently building a Website using WebApi, MVC and AngularJS and I was wondering how I could know from which location the User is browsing my website…

So I decided to make some research and I found a Web Service that takes as parameter an IP Address and gives you back the XML Response with details which include:

<Response>
<IP>00.00.00.00</IP>
<CountryCode>MT</CountryCode>
<CountryName>Malta</CountryName>
<RegionCode>32</RegionCode>
<RegionName>Il-Mosta</RegionName>
<City>Mosta</City>
<ZipCode/>
<TimeZone>Europe/Malta</TimeZone>
<Latitude>35.909</Latitude>
<Longitude>14.426</Longitude>
<MetroCode>0</MetroCode>
</Response>

I Changed the Ip Address to 00 for protection…

You can however try this with your IP Address:

http://freegeoip.net/xml/INSERT_YOUR_IP_HERE

I decided to create some clean code for this approach… Basically what I did consisted of creating a BaseMvcController – Or you can create a BaseApiController to get the Request Details and I created a class to hold this data…

public class RequestDetails
    {
        public DateTime TimeStamp { get; set; }
        public string CallerIp { get; set; }
        public string CallerAgent { get; set; }
        public string CalledUrl { get; set; }
    }
    
    //this is used for Web Api base controller
   public RequestDetails DownloadRequestDetails()
   {
       var requestModel = new RequestDetails
       {
           TimeStamp = DateTime.Now,
           CallerIp = HttpContext.Current.Request.UserHostAddress,
           CallerAgent = HttpContext.Current.Request.UserAgent,
           CalledUrl = HttpContext.Current.Request.Url.OriginalString
       };
       return requestModel;
   }
   
   //this is used for MVC Base Controller
   public RequestDetails DownloadRequestDetails()
   {
       var requestModel = new RequestDetails
       {
           TimeStamp = DateTime.Now,
           CallerIp = System.Web.HttpContext.Current.Request.UserHostAddress,
           CallerAgent = System.Web.HttpContext.Current.Request.UserAgent,
           CalledUrl = System.Web.HttpContext.Current.Request.Url.OriginalString
       };
       return requestModel;
   }

I did it in a base controller, so that every time I needed this data I could call it directly from any controller that inherits from it.

I also had to create a class to hold the XML data which is generated for response from the Free Geo Ip web service:

[XmlRoot("Response")]
    public class IpAddressDetails
    {
        [XmlElement("Ip")]
        public string Ip { get; set; }
        [XmlElement("CountryCode")]
        public string CountryCode { get; set; }
        [XmlElement("CountryName")]
        public string CountryName { get; set; }
        [XmlElement("RegionCode")]
        public string RegionCode { get; set; }
        [XmlElement("RegionName")]
        public string RegionName { get; set; }
        [XmlElement("City")]
        public string City { get; set; }
        [XmlElement("ZipCode")]
        public string ZipCode { get; set; }
        [XmlElement("Latitude")]
        public double Latitude { get; set; }
        [XmlElement("Longitude")]
        public double Longitude { get; set; }
        [XmlElement("MetroCode")]
        public string MetroCode { get; set; }
        [XmlElement("AreaCode")]
        public string AreaCode { get; set; }
    }

So now I have the IP Address of the User, I now need to call the service and download information about that IP Address..

private const string HttpFreegeoipNetXML = "http://freegeoip.net/xml/{0}";

public IpAddressDetails DownloadIpAddressDetails(RequestDetails requestDetails, string userId)
{
  var ipAddressDetails = new IpAddressDetails();
  
    //this is useful since when running on localhost your ip address will return ::1 
    #if DEBUG
    //insert your ip address here
    requestDetails.CallerIp = "00.00.00.00";
    #endif
    //caching is being used so that if I already have the IP Address details I don't re download them again...
  string cacheKey = requestDetails.CallerIp + userId;
  if (_cacheStoreService.IsSet(cacheKey))
  {
      return (IpAddressDetails)_cacheStoreService.Get(cacheKey);
  }
  try
  {
        //create a web client
      using (var objClient = new WebClient())
      {
            //download the contents from the URL
            //HttpFreegeoipNetXML contains this url "http://freegeoip.net/xml/{0}"
          var ipAddressXml = objClient.DownloadString(string.Format(HttpFreegeoipNetXML, requestDetails.CallerIp));
            //init an XML Serializer
          var ser = new XmlSerializer(typeof(IpAddressDetails));
            //Deserialize the response string received and cast it to the Class I created to hold the Ip Details data
          ipAddressDetails = (IpAddressDetails)ser.Deserialize(new StringReader(ipAddressXml));
            //set the new ip address in the cache store                    
          _cacheStoreService.Set(cacheKey, ipAddressDetails, TimeSpan.FromDays(20));
      }
  }
  catch (Exception ex)
  {
      _logger.Error("Error getting geo location for ip address: " + requestDetails.CallerIp, ex);
      return new IpAddressDetails();
  }

  return ipAddressDetails;
}

What I  did here is;

I started a webclient and made a request to http://freegeoip.net/xml/{0} with the ip address of the user

I then Deserialzed the string and cast it into the new type I created to hold the location details.

Read the comments I made to understand exactly what the code is doing!!

I hope you find this post useful

<Response>
<IP>00.00.00.00</IP>
<CountryCode>MT</CountryCode>
<CountryName>Malta</CountryName>
<RegionCode>32</RegionCode>
<RegionName>Il-Mosta</RegionName>
<City>Mosta</City>
<ZipCode/>
<TimeZone>Europe/Malta</TimeZone>
<Latitude>35.909</Latitude>
<Longitude>14.426</Longitude>
<MetroCode>0</MetroCode>
</Response>

Leave a Reply

Your email address will not be published. Required fields are marked *