65.9K
CodeProject 正在变化。 阅读更多。
Home

CountryListBox ASP.NET Web 控件,列出国家并自动检测访问者的国家。

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (20投票s)

2002年12月2日

6分钟阅读

viewsIcon

256479

downloadIcon

5029

一个派生自 DropDownList 的控件,该控件列出所有国家,并执行 IP 地址数据库查找,以自动确定访问者的国家。

引言

本文的目的是展示如何创建一个更专业的 DropDownList Web 控件 - 特别是用于显示国家的控件 - 适用于 ASP.NET Web Forms。其主要优点是(不仅显示所有国家,手动添加每个国家到 HTML 会非常繁琐),而且它还可以自动识别访问者来自哪个国家,或者说,访问者正在访问网站的哪个国家。

该 Web 控件使用来自 MaxMind 的数据库,特别是其 GeoIP Free Database。MaxMind 还提供了一个 C# 类来访问其数据库。

这是一个非常简单的控件,大部分工作由现成的 CountryLookup 类完成,因此最好的方法是概述它的工作原理,然后介绍实现细节。

一如既往,我的网站上提供了一个 实时演示

工作原理

总的来说,CountryListBox Web 控件派生自 DropDownList,并将一个 ASCII 文本文件的内容添加到 CountryListBoxItems 集合中(国家列表)。MaxMind 提供了一个 CountryLookup 类,该类包含一个每个国家的字符串数组 - 创建了一个实用程序来将这个数组的内容转储到一个 ASCII 文本文件中。数组的一部分包含“N/A”和“Anonymous Proxy”,这些内容已从文本文件中移除。这个文本文件包含在两个存档中,所以您不必担心重新创建它。

在加载完国家列表后,会根据 IP 数据库进行查找以确定当前访问者的位置,然后将其选中在下拉列表中 - 允许用户在错误时进行更正。除此之外,它的行为与任何其他 DropDownList 控件一样。

现在是 MaxMind GeoIP 数据库背后的技术细节(理解这些并非绝对必要,因为 C# 类是由 MaxMind 提供的)。

MaxMind 存储 IP 地址范围,每个记录也都会标记一个国家。例如(CSV 格式),"1029177344","1029439487","AU","Australia"。IP 地址计算方法是 ipnum = 16777216*w + 65536*x + 256*y + z。例如,根据 24.24.24.24 计算 IP 号码:404232216 = 16777216*24 + 65536*24 + 256*24 + 24。所有这些都由 CountryLookup 类处理 - 该类可直接从 MaxMind 下载(但已包含在 CountryListBox 程序集中)。

实现细节

该控件的设计相对简单,大部分工作是在 OnInit 重写方法中完成的。其目的是将所有国家添加到控件的 Items 集合中,然后选择访问者所在的国家。

OnInit

下面是 OnInit 方法的部分代码。它包括确定是否应使用应用程序缓存来存储 Geo IP 数据库的代码(通过 CountryListBoxCacheDatabase 属性设置)。如果使用缓存,并且检测到数据尚未存储,它会将文件加载到一个 MemoryStream 对象中(这是通过 FileToMemory 静态方法实现的 - 我将其添加到 CountryLookup 类中)。然后,这个 MemoryStream 对象会被存储在应用程序缓存中。

// Check to see if the application cache should be used
if (useAppCache)
{
  // Check to see whether the IP Database is
  // already in the Application Cache
  if (Context.Cache.Get("GeoIPData") == null)
    // No, so store it as well as setting a dependency on the file
    Context.Cache.Insert("GeoIPData",
       CountryLookup.FileToMemory(
         ConfigurationSettings.AppSettings["GeoDatFile"]),
         new CacheDependency
           (ConfigurationSettings.AppSettings["GeoDatFile"]));

然后调用 LoadCountries 方法来填充 Items 集合,并进行查找,然后选择匹配的国家。

    // Load the countries from the ASCII file into the control
    LoadCountries();

    // Perform the lookup using the MemoryStream taken from the Cache
    CountryLookup cl = new CountryLookup(
        ((MemoryStream)Context.Cache.Get("GeoIPData"))
        );

    // What country is the visitor from?
    string visitorCountry = cl.lookupCountryName(
        this.Page.Request.ServerVariables["REMOTE_ADDR"]
        );

    // Select the country in the control
    this.SelectedIndex = this.Items.IndexOf(
        new ListItem(visitorCountry,visitorCountry)
        );
}

CountryLookup 更改

CountryLookup 类由 MaxMind 提供,因此需要进行一些更改才能在存储在内存中的数据库上执行搜索。由于 .NET 的流基础设施,这变得相当容易。

部署演示

演示中包含一个测试 Web 窗体、GeoIP 数据库、国家文本文件和 CountryListBox 程序集。目录结构已准备好复制,但需要更改 *web.config* 中的内容以反映不同的路径。您可以将这些文件放在任何地方(例如,公共可访问文件结构之外),只需确保 ASP.NET 用户帐户具有必要的访问权限。

您需要做一些基本的事情才能将控件添加到您的页面:

  1. 在页面顶部添加导入语句
    <%@ Register TagPrefix="etier" Namespace="Etier" 
                             Assembly="CountryListBox" %>
  2. 然后在页面中添加该标签,它应该支持任何标准的 DropDownList 属性(尽管我没有对此进行彻底测试 :))
    <etier:CountryListBox
      Id="MyListBox"
         RunAt="server"
      CacheDatabase=true
      CacheCountries=true
    />

性能

我对控件进行了有限的测试,以了解它在负载下的性能。我使用 Windows XP Professional 作为开发平台,该平台具有受限制的 IIS 版本 - 限制为 10 个并发连接。我使用 Microsoft Application Center Test 进行测试,测试涉及在 5 分钟内尽可能多地加载演示页面。

非缓存版本结果

下方的图表显示了使用标准控件(无缓存)的测试结果。每次请求页面时,都会加载并搜索 GeoIP 数据库文件,并且还会从文本文件中加载国家。图表下方是一些测试期间记录的基本统计数据。

Average requests per second: 32.47
  Average time to first byte (msecs): 279.39 
  Average time to last byte (msecs): 279.55 
  
  Response Code: 403 - The server understood the request, but is refusing 
  to fulfill it. 
  Count: 5,429
  Percent (%): 55.73 
  
  
  Response Code: 200 - The request completed successfully. 
  Count: 4,313 
  Percent (%): 44.27

由于我的本地机器并不是真正设计用来作为服务器(它是一台基于 Athlon XP 2000+ 的机器,拥有 512MB RAM,但没有 SCSI 硬盘),因此可以公平地假设专用服务器的性能会更好。尽管如此,该服务器每秒只能处理平均 32 个请求。

缓存结果

为了提高性能,我使用了 ASP.NET 的应用程序缓存来存储 GeoIP 数据库和国家列表。可以通过 CacheDatabaseCacheCountries 属性来设置使用这两者的选项。然后我运行了相同的测试脚本,下面的结果图表显示了显着的差异(远远超出我的预期)。同样,下方包含一些基本统计数据。

Average requests per second: 146.01 
  Average time to first byte (msecs): 43.48 
  Average time to last byte (msecs): 43.76 
  
  
  Response Code: 403 - The server understood the request, but is refusing 
  to fulfill it. 
  Count: 6 
  Percent (%): 0.01 
  
  
  Response Code: 200 - The request completed successfully. 
  Count: 43,797 
  Percent (%): 99.99

由于缓存,每秒可处理的请求数量已从 32 个增加到 146 个,增长了约 350%。

结论

感谢 Per Soderlind 撰写了一篇文章,该文章首先告诉我 MaxMind 的 GeoIP 数据库。也感谢 MaxMind 免费提供数据库。似乎它对商业应用程序也是免费的 -- 但也提供商业服务,包括区域、州甚至 NetBlock 所有者的详细信息!

这是一个非常简单的控件,但它也非常有用!它应该可以防止这么多人错误地填写表格。再次,如果您有任何意见或问题,请随时通过电子邮件与我联系,或者在下方发布消息。

© . All rights reserved.