Target Your Visitors Using GeoIP and .NET
While the Internet is a global phenomenon that connects different people in different countries, many sites fail to target their content or functionality to visitors who speak languages other than English, or who live outside countries with the largest Internet user bases, like America. But, with nations like China using the Internet more and more, English-only is no longer a smart decision.
It’s time to get smart. If you think that providing your site in another language will be a huge hassle, think again.
GeoIP API, combined with your .NET Web applications, can create pages whose content is specifically tailored to the user on the basis of their geographical location — this article will show how it’s done. By the time we’ve finished, you’ll be able to use GeoIP API and .NET to increase visitor satisfaction and, potentially, ad revenues for your site.
GeoIP
GeoIP is a product from MaxMind that maps given IP addresses to specific locations stored in a database of IP addresses.
Different editions of GeoIP are available, but you can use the free edition of the country database to get 93% accurate mappings within your applications. Do check the licensing information to make sure your particular app is suitable for the free use option.
MaxMind also provide a C# API, which we’ll use in this article. You need to download both the API and the free country database to be able to use the code in this article:
Internationalization in .NET
ASP.NET comes with some great internationalization features. Date, time, and currency formatting are dependent on the "culture" being used at any point in the application. For example, to a user with a British culture (defined by the RFC 1766 country code "en-gb"), a date would be displayed in the following form:
DD/MM/YYYY
With the culture set to American English ("en-us"), the form would take the following:
MM/DD/YYYY
A user interface culture is exposed by ASP.NET. This UICulture
value is used to determine which resources to display on a Web form, for example, resource strings from a database, or specific images for specific cultures.
There are many ways to set these cultures for an application, or a specific page. One method is to use the configuration file of the application (web.config) like so:
<configuration>
<system.web>
<globalization fileEncoding="utf-8" requestEncoding="utf-8" responseEncoding="utf-8" culture="en-US" uiCulture="de-DE" />
</system.web>
</configuration>
The globalization entry defines the various ways a page is to be encoded (useful for displaying languages with non-English characters) as well as the Culture
and UICulture
values talked about earlier.
In the above example, the application culture is set to American English ("en-US") while the user interface culture is set to German ("de-DE"). This is particularly useful in ecommerce sites, for example, as it means you can display price information in dollars, yet have the page output tailored for a German audience.
You can also set the culture of a specific form in its page directive:
<%@ Page UICulture="de-DE" Culture="en-US" %>
Note, however, that both these methods will set the culture for all the form’s viewers. In this tutorial, we’ll find the culture of a visitor by consulting the GeoIP database, then use the appropriate culture for that visitor.
Dynamic Globalization
ASP.NET applications create a new thread for each request. We can change the properties of the thread to tailor the application’s behaviour for a given user without altering its behaviour for other visitors.
The entry point to ASP.NET applications is the Application_BeginRequest()
method in the global.asax
file. Once we’ve determined and set the culture of the visitor here, the content that’s displayed will be tailored to specifically to them.
Specifying the cultures in code is done by setting the thread’s CurrentCulture
and CurrentUICulture
properties to a CultureInfo
object, which represents the culture we wish to use. In this example, the culture is set to German ("de-DE"):
CultureInfo userCulture = new CultureInfo.CreateSpecificCulture("de-DE");
System.Threading.CurrentThread.CurrentCulture = userCulture;
System.Threading.CurrentThread.CurrentUICulture = userCulture;
The information we need to grab from GeoIP is the RFC 1766
code. This will let us create the correct CultureInfo
object.
Using GeoIP
The GeoIP C# API exposes a method to find country information from an IP address’s lookupCountryCode
. The current user’s IP address can be sought through the value in Request.UserHostAddress
, which will pass to this method to receive a country code:
//import the geoip API
using CountryLookupProj;
protected void Application_BeginRequest(Object sender, EventArgs e)
{
string strCulture;
try
{
CountryLookup cl = new CountryLookup(Server.MapPath("GeoIP.dat"));
strCulture = cl.lookupCountryCode(Request.UserHostAddress);
}
catch
{
//this is our default culture if GeoIP fails to make a match
strCulture = "en-US";
}
CultureInfo userCulture = new CultureInfo.CreateSpecificCulture(strCulture);
System.Threading.CurrentThread.CurrentCulture = userCulture;
System.Threading.CurrentThread.CurrentUICulture = userCulture;
Session["userCulture"] = strCulture;
}
The above code locates the country code from GeoIP, creates a CultureInfo
object to represent it as a culture, then sets the current application thread to this new culture. The last line adds this country code to the user’s session cookie for quick reference later.
A Drop-Down Country Selector
Having identified a culture, we can begin to customise pages to our users. One way to do this is to create a drop-down list that automatically highlights users’ countries for them.
To start, we need to fill a drop-down box with all the countries recognised by GeoIP. We can do this by parsing the 2 arrays countryName
and countryCode
, provided by the API in the countryLookUp
class (countryLookUp.cs
), and creating ListItem
objects to add to the drop-down list from their values.
Note that the 2 arrays are not, by default, exposed by the API (they are marked as private). You can either publicise or copy the arrays into the form on which you wish to use the drop down box.
The first method is to change the countryLookUp
class to publicly expose the arrays through accessors. Add the following bolded lines to the class:
public class CountryLookup
{
private FileStream fileInput;
private static long COUNTRY_BEGIN = 16776960;
public static string[] CountryCode
{
get
{
return countryCode;
}
}
public static string[] CountryName
{
get
{
return countryName;
}
}
Now that we’ve exposed the arrays within the API to our application, we can parse them to fill our drop-down list box:
//import the geoip API
using CountryLookupProj;
private void Form1_Load(object sender, System.EventArgs e)
{
for (int i = 0; i < countryLookup.CountryName.Length; i++)
{
ListItem l = new ListItem(countryLookup.CountryName[i],
countryLookup.CountryCode[i]);
DropDownList1.Items.Add(l);
}
}
We can now automatically select from the user’s session cache the item with the value of our culture country code:
DropDownList1.Items.FindByValue(Session["userCulture"]).Selected = true;
Executing the application, the drop down list automatically finds the user’s location, and, using his or her IP address, selects the correct entry in the drop-down list:
Targeted Advertisements
You can extend this idea to create targeted advertisements based on users’ locations. For example, a user in Germany will be far more likely to click on an ad that displays a German product than one designed for American audiences.
This task can be achieved in numerous ways. This section will outline one method by which we can randomly select an appropriate ad from the database, each ad having assigned to it country codes reflecting the users to which it should be displayed.
We’ll use a very simple database table to store the image location and the associated country code. This can be extended to allow for two tables, one containing the image URLs and one for associated country codes, linked via a foreign key.
Our table is thus:
CREATE TABLE Adverts
{
ID int IDENTITY (1,1) NOT NULL,
ImageLocation varchar(200) NOT NULL,
CountryCode varchar(2) NOT NULL
}
When we come to display our ad, we can select all the ads that correspond to our country code using the following SQL statement:
SELECT TOP 1 ImageLocation FROM Adverts WHERE CountryCode = "GB" ORDER BY NEWID()
Notice the use of ORDER BY NEWID()
. In SQL Server, this lists the records in pseudo-random order. By only selecting TOP 1
, we’re effectively selecting a single random record.
Hence, using an Image web control (Image1) on our form, we can query the database thus:
string sqlConn = "connectionstring";
string sqlCmd = "SELECT TOP 1 ImageLocation FROM Adverts WHERE CountryCode = '"+Session["userCulture"]+"' ORDER BY NEWID()";
SqlConnection myConnection = new SqlConnection(sqlConn);
SqlCommand cmdRandomQuote = new SqlCommand(sqlCmd, myConnection);
myConnection.Open();
SqlDataReader myReader = cmdRandomQuote.ExecuteReader();
myReader.Read();
//Set the advert
Image1.Location = myReader["ImageLocation"].ToString();
myConnection.Close();
Summary
By being aware of users from different nationalities who speak different languages, and using the techniques outlined in this article, you can create truly global applications with minimum effort.