Download solution
Introduction
In a previous article (WURFL ASP.NET Implementations) I presented a comparison of 3 ASP.NET WURFL libraries for querying the capabilities of mobile devices. This current article takes one of the implementations (WURFL.Marg) which proved the best performer, and creates a wrapper class for it. The library (class) exposes consistent high level objects, creates an object hierarchy (as opposed to a flat collection of type string), caches the objects with a dependency on the data file, and shares this data across many web-applications.
Background
The decision to create a wrapper class rather than extend the existing source files was based on loose coupling.
- If the source for
WURFL.Marg
is altered by the maintenance developers, as long as the used method signatures are not altered, this wrapper class should still function correctly, with minor alterations.
- The wrapper class is not implementation specific - if another WURFL library is chosen instead of
WURFL.Marg
then the cutover will be quite simple.
Sharing the data files is not such a big deal is it? Well yes and no. It is supported out of the box with WURFL.Marg
but caching isn't. Once dependency-centric caching is provided, special consideration is needed for the shared location of the data file (WURFL.xml - the device capability data).
The caching itself is not complex - the object heirachy needs to be considered, and a reload of the cache is needed when the data file is modified. This is acheived using the System.Web.Caching.Cache
class, setting a CacheDependency
object for the WURFL.xml file and using a deffered event via the CacheItemRemovedCallback
class for reloading the cache once the data file has been modified.
The same metrics were applied for the wrapper class as were applied to the three WURFL implementations in the previous article. The Tests steps were:
- user agent: current device
capability: mobile_browser
data modified: false
- user agent: current device
capability: xhtml_table_support
data modified: false
- user agent: current device
capability: ajax_support_javascript
data modified: false
- user agent: current device
capability: resolution_width
data modified: false
- user agent: NokiaN92-2
capability: mobile_browser
data modified: false
- user agent: NokiaN92-2
capability: xhtml_table_support
data modified: false
- user agent: NokiaN92-2
capability: ajax_support_javascript
data modified: false
- user agent: NokiaN92-2
capability: resolution_width
data modified: false
- user agent: iPhone
capability: mobile_browser
data modified: true
The results were:
The wrapper class was tested with the strongly typed hierarchy of capabilities (including intellisense) and without those properties. The differences were negligible; the strongly typed capabilities did not prove a performance hit. The differences in tests #1 & #5 can be attributed to the cache being loaded and is worth the "hit". The obvious difference is in test #9 - this is a desirable result. This indicates that as the data file is modified on the server, the cache was being reloaded; this did not happen with any of the previous WURFL implementations tested.
The following diagram shows the hierarchy of capabilities and the supporting intellisense:
Using the code
Both WURFL.Marg
and emx.tcp.mobile
are used and they will be needed to be added as a reference to the Web Application/Website project. log4net
will be added to the bin as a dependency (of WURFL.Marg
) and is not necessary as a reference.
The web.config file will need the base WURFL.Marg
edits listed below:
The log4net
and browserCaps
sections are optional.
The uses of the shared methods are very simple. The querying of capabilities of the current device using the original flat collection and the strongly typed object is:
Response.Write(
emx.tcp.mobile.Device.currentDevice()
.capabilities["resolution_height"].value + "<br/>");
Response.Write(
emx.tcp.mobile.Device.currentDevice()
.display.resolutionHeight + "<br/>");
The querying of capabilities of a referred device (with user-agent) using the original flat collection and the strongly typed object is:
Response.Write(
emx.tcp.mobile.Device.referredDevice("NokiaN92-2")
.capabilities["resolution_height"].value + "<br/>");
Response.Write(
emx.tcp.mobile.Device.referredDevice("NokiaN92-2")
.display.resolutionHeight + "<br/>");
All the caching and object instantiation is performed in the background - simple and easy...
Points of Interest
Unfortunately the the referredDevice
object has full Caching/Dependency awareness and the currentDevice
hasn't. The currentDevice
instantiation took (indirectly) the user-agent as a parameter - so, in practical terms, its only good for the length of the session. Therefore the currentDevice
is stored in the Session
dictionary. A new method has been added (loadCurrentCache
) which can be called from the SessionStart
event.
Future Enhancements
I am adding some logging (user-agent, application etc) code for my current project, and intend to mine that to cache and index the most widely used user-agents - if this process is modular enough I will add it to this library...
History
- 2009-02-09 -
currentDevice
stored in Session dictionary
- 2009-02-07 - Article submitted