Code

Finally got around to updating my website - fixed the final "missing DLLs" error about 10:30 PM.
5:00 AM and I have a ping from my phone from the Contact page, (it's Russian spam/crap, but at least I've got an IP Address from that f*cker).
Now, I've blocked IPs before, but I need to block a whole *country*, and I:
  • don't have full access to IIS with my host
  • am aware that blocking an entire country by IP Address is futile, at best
WHOIS is great for IP lookups, but my site's not going to get enough traffic to justify paying for a lookup service, and with > 26K of a response, parsing through the HTTP Response is out of the question. Brute-force string parsing is very outdated, though still satisfying, if not outright fun.

The old code

I was originally using api.iplocation.net, it is free with a basic amount of returned info, and it works just fine. However, it doesn't include Latitude/Longitude, which I've decided to use.
Click below to see the original implementation code.
show api.iplocation.net code...
Using the following definitions in Misc.cs:

		public static string IPLOCATION_BASE   = "https://api.iplocation.net/";
		public static string IPLOCATION_PARAMS = "&ip=";
		
		public static SecurityProtocolType _SECURITY_PROTOCOL_TYPE_ = SecurityProtocolType.Tls12;


...with the following code snippet:

		public IpLocation GetCountryCodeEx(string ip)
		{
			ServicePointManager.SecurityProtocol = Misc._SECURITY_PROTOCOL_TYPE_;

			IpLocation objRet = null;

			using (HttpClient client = new HttpClient())
			{
				string url = Misc.IPLOCATION_BASE;
				client.BaseAddress = new Uri(url);

				string parameters = Misc.IPLOCATION_PARAMS + ip;

				HttpResponseMessage response = client.GetAsync(parameters).Result;
				if (response.IsSuccessStatusCode)
				{
					var json = response.Content.ReadAsStringAsync().Result;

					objRet = JsonConvert.DeserializeObject<IpLocation>(json);
				}
			}

			return objRet;
		}

...gives the following JSON response:

		[JSON]
			ip: "123.456.789.101"
			ipnumber: "numeric equivalent"
			ip_version: 4
			country_name: "Russian Federation"
			country_code2: "RU"
			isp: "Siberian Telecommunications Ltd."
			response_code: "200"
			response_message: "OK"
							
So, properly declare for JSON to package up (some) return params, and we'll have CountryName available:

		public class IpLocation
		{
			[JsonProperty("ip")]
			public string Ip { get; set; }

			[JsonProperty("ip_version")]
			public int IpVersion { get; set; }

			[JsonProperty("country_name")]
			public string CountryName { get; set; }

			[JsonProperty("country_code2")]
			public string CountryCode { get; set; }

			[JsonProperty("isp")]
			public string ISP{ get; set; }
		}

The new code

geolocation-db.com, is what I settled on - it has roughly the same basic info as api.location.net, and includes latitude/longitude.
Let's take a look at the REST call.
Using the following definitions in Misc.cs:

public static string GEO_LOCATION_DB_BASE   = "https://geolocation-db.com/json/";
public static string GEO_LOCATION_NOT_FOUND = "Not found";
	
public static SecurityProtocolType _SECURITY_PROTOCOL_TYPE_ = SecurityProtocolType.Tls12;


And grabbing a GUID from web.config (geolocation-db.com requires simple email registration and provides a GUID to use):

<add key="GeoLocationDb_Key" value="{GUID}" />

#region GEO Location Db

private static string _GeoLocationDbKey = "";
public static string GeoLocationDbKey
{
	get { return _GeoLocationDbKey; }
}

public static void LoadGeoLocationDbKey()
{
	_GeoLocationDbKey = ConfigurationManager.AppSettings["GeoLocationDb_Key"].ToString();
}

#endregion

...with the following code snippet:
(Notice that you may get back null (the value) or "Not found", so these are checked for in order to give a clean return object.)

public GeoLocation GetGeoLocation(string ip)
{
	ServicePointManager.SecurityProtocol = Misc._SECURITY_PROTOCOL_TYPE_;

	GeoLocation objRet = null;

	using (HttpClient client = new HttpClient())
	{
		string url = Misc.GEO_LOCATION_DB_BASE + Misc.GeoLocationDbKey + "/" + ip;

		HttpResponseMessage response = client.GetAsync(url).Result;
		if (response.IsSuccessStatusCode)
		{
			var json = response.Content.ReadAsStringAsync().Result;

			objRet = JsonConvert.DeserializeObject<GeoLocation>(json);

			// fix up if any NULLs or "Not found"
			if (objRet.Ip == null || objRet.Ip == Misc.GEO_LOCATION_NOT_FOUND) objRet.Ip = "";

			if (objRet.CountryName == null || objRet.CountryName == Misc.GEO_LOCATION_NOT_FOUND) objRet.CountryName = "";
			if (objRet.CountryCode == null || objRet.CountryCode == Misc.GEO_LOCATION_NOT_FOUND) objRet.CountryCode = "";

			if (objRet.City   == null || objRet.City   == Misc.GEO_LOCATION_NOT_FOUND) objRet.City = "";
			if (objRet.State  == null || objRet.State  == Misc.GEO_LOCATION_NOT_FOUND) objRet.State = "";
			if (objRet.Postal == null || objRet.Postal == Misc.GEO_LOCATION_NOT_FOUND) objRet.Postal = "";

			if (objRet.strLatitude  == null || objRet.strLatitude  == Misc.GEO_LOCATION_NOT_FOUND) objRet.strLatitude  = "0";
			if (objRet.strLongitude == null || objRet.strLongitude == Misc.GEO_LOCATION_NOT_FOUND) objRet.strLongitude = "0";
		}
	}

	return objRet;
}

...gives the following JSON response:

[JSON]
	country_code: "US"
	country_name: "United States"
	city: "Anyville"
	postal: "01210"
	latitude: "12.3456"
	longitude: "78.6543"
	IPv4: "123.456.789.101"
	state: "Massachusetts"
					
So, properly declare for JSON to package up the return params, along with (2) helpers for Latitude/Longitude:

public class GeoLocation
{
	[JsonProperty("IPv4")]
	public string Ip { get; set; }

	[JsonProperty("country_code")]
	public string CountryCode { get; set; }

	[JsonProperty("country_name")]
	public string CountryName { get; set; }

	[JsonProperty("city")]
	public string City { get; set; }

	[JsonProperty("state")]
	public string State { get; set; }

	[JsonProperty("postal")]
	public string Postal { get; set; }

	[JsonProperty("latitude")]
	public string strLatitude { get; set; }

	[JsonProperty("longitude")]
	public string strLongitude { get; set; }

	public double Latitude { get { return double.Parse(strLatitude); } }

	public double Longitude { get { return double.Parse(strLongitude); } }
}