抽象、缓存和共享 WURFL
ASP.NET 中简单易用的移动设备功能查询。

引言
在上一篇文章(WURFL ASP.NET 实现)中,我比较了 3 个 ASP.NET WURFL 库,用于查询移动设备的功能。本文将选取其中一个性能最好的实现(WURFL.Marg),并为其创建一个包装类。该库(类)公开了一致的高层对象,创建了一个对象层次结构(而不是扁平的字符串集合),缓存对象并依赖于数据文件,并将此数据跨多个 Web 应用程序共享。
背景
决定创建包装类而不是扩展现有源文件是基于松耦合的考虑。
- 如果
WURFL.Marg
的源文件被维护开发人员修改,只要所使用的方法签名未被更改,此包装类仍应能正常工作,只需稍作修改。 - 该包装类不特定于实现——如果选择
WURFL.Marg
以外的其他 WURFL 库,切换将非常简单。
共享数据文件似乎不是什么大问题,是吗?嗯,有好有坏。WURFL.Marg
开箱即支持此功能,但缓存功能不支持。一旦提供了依赖项中心缓存,就需要特别考虑数据文件(WURFL.xml - 设备功能数据)的共享位置。
缓存本身并不复杂——需要考虑对象层次结构,并且在数据文件修改时需要重新加载缓存。这通过 System.Web.Caching.Cache
类实现,为 WURFL.xml 文件设置 CacheDependency
对象,并使用 CacheItemRemovedCallback
类通过延迟事件在数据文件修改后重新加载缓存。
包装类与上一篇文章中对三个 WURFL 实现应用的指标相同。测试步骤是:
- 用户代理:当前设备
功能:mobile_browser
数据已修改:false - 用户代理:当前设备
功能:xhtml_table_support
数据已修改:false - 用户代理:当前设备
功能:ajax_support_javascript
数据已修改:false - 用户代理:当前设备
功能:resolution_width
数据已修改:false - 用户代理:NokiaN92-2
功能:mobile_browser
数据已修改:false - 用户代理:NokiaN92-2
功能:xhtml_table_support
数据已修改:false - 用户代理:NokiaN92-2
功能:ajax_support_javascript
数据已修改:false - 用户代理:NokiaN92-2
功能:resolution_width
数据已修改:false - 用户代理:iPhone
功能:mobile_browser
数据已修改:true
结果如下:
包装类已在具有强类型功能层次结构(包括智能感知)和不带这些属性的情况下进行了测试。差异微乎其微;强类型功能并未带来性能损失。测试 #1 和 #5 中的差异可归因于缓存已加载,这值得“一次性的开销”。明显的差异出现在测试 #9——这是一个理想的结果。这表明当数据文件在服务器上被修改时,缓存被重新加载;这在之前测试过的任何 WURFL 实现中都没有发生。
下图显示了功能层次结构和支持的智能感知
使用代码
WURFL.Marg
和 emx.tcp.mobile
都会被使用,并且需要将它们添加为 Web 应用程序/网站项目的引用。log4net
将作为依赖项(WURFL.Marg
的依赖项)添加到 bin 文件夹,不需要作为引用。
web.config 文件将需要下面列出的 WURFL.Marg
的基本编辑
log4net
和 browserCaps
部分是可选的。
共享方法的使用非常简单。使用原始的扁平集合和强类型对象查询当前设备的功能是:
// flat WurflDeviceIndex collection
Response.Write(
emx.tcp.mobile.Device.currentDevice()
.capabilities["resolution_height"].value + "<br/>");
// strongly typed equivilent object
Response.Write(
emx.tcp.mobile.Device.currentDevice()
.display.resolutionHeight + "<br/>");
使用原始的扁平集合和强类型对象查询推荐设备(带用户代理)的功能是:
// flat WurflDeviceIndex collection
Response.Write(
emx.tcp.mobile.Device.referredDevice("NokiaN92-2")
.capabilities["resolution_height"].value + "<br/>");
// strongly typed equivilent object
Response.Write(
emx.tcp.mobile.Device.referredDevice("NokiaN92-2")
.display.resolutionHeight + "<br/>");
所有缓存和对象实例化都在后台执行——简单易用...
关注点
不幸的是,referredDevice
对象具有完整的缓存/依赖项感知功能,而 currentDevice
则没有。currentDevice
的实例化(间接)以用户代理作为参数——因此,实际上,它只在会话期间有效。因此,currentDevice
被存储在 Session
字典中。已添加一个新方法(loadCurrentCache
),可以从 SessionStart
事件调用。
未来的增强
我正在为当前项目添加一些日志记录(用户代理、应用程序等)代码,并打算从中挖掘数据,缓存和索引最常用的用户代理——如果这个过程足够模块化,我会将其添加到这个库中...
历史
- 2009-02-09 -
currentDevice
存储在 Session 字典中 - 2009-02-07 - 文章提交