ASP.Net Validating Culture Names

Adam picture Adam · Jan 26, 2009 · Viewed 9.4k times · Source

We have a multilingual site that utilizes asp.net 2.0 cultures. The current culture is set through the url rewritten as a query string. (~/es/blah.aspx is the spanish version of ~/blah.aspx - rewritten as ~/blah.aspx?lang=es)

The code that tests the culture is as follows:

    System.Globalization.CultureInfo ci;
    try
    {
        ci = new System.Globalization.CultureInfo(Request.QueryString["lang"] ?? string.Empty);
    }
    catch
    {
        ci = new System.Globalization.CultureInfo(string.Empty);
    }

If there is no culture set, it defaults to english, 127. When there is a culture, all links on that page are then pre-pended with the correct culture name.

Some how or another a spider got a hold of a few links in the form of ~/www.test.com/blah.aspx and is hammering our site with a culture of www.test.com which and flooding our error logging.

Is there any way to test whether a culture name is valid besides catching an exception?

Answer

BenCr picture BenCr · Sep 11, 2012

I thought I'd have a quick go at measuring this so knocked up a quick console application.

It basically uses all 3 methods (constructor, LINQ and foreach) to get a CultureInfo from a string 10000 times in a loop. I removed the stopwatch and console output for brevity.

string culture = "en-GB";
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
for (int i = 0; i < 10000; i++)
{
    try
    {
        CultureInfo c = new CultureInfo(culture);
    }
    catch
    {
    }
}
for (int i = 0; i < 10000; i++)
{
    CultureInfo c = cultures.FirstOrDefault((x) => x.Name == culture);
}
for (int i = 0; i < 10000; i++)
{
    foreach (CultureInfo c in cultures)
    {
        if (c.Name == culture)
            break;
    }
}

The results are as follows...

Try Catch: 00:00:00.0023860
LINQ: 00:00:00.0542459
ForEach: 00:00:00.0238937

If you remove the cultures variable and call it each iteration then the LINQ and ForEach loops take about 2.5 seconds.

So, using the constructor is favourable if you expect to get lots of valid inputs and only the odd invalid one. But if you change the value if the input from en-GB to TEST then things change massively.

Invalid Culture Try Catch: 00:00:39.7163513
Invalid Culture LINQ: 00:00:00.0791752
Invalid Culture ForEach: 00:00:00.0291480

Obviously my test application isn't a real world scenario but since the OP said this is called on a per request basis I can imagine that in a large web application this code could get called a lot. It's possibly a denial or service vector, take up all the CPU by spamming the web server with requests that all have an invalid culture parameter.