An application that uses WURFL is
simply an application that needs to check a number of
effective browser capabilities in order to decide what to serve. The
WURFL database contains information about a huge
number of devices and mobile browsers. This information essentially
consists in a list of over 500 capabilities. Each device,
uniquely identified by its user-agent string (UAS), falls into a group
and inherits the capabilities defined for the group,
plus the delta of base capabilities that make it unique.
Programming a WURFL-based application
is therefore a fairly easy task. All you need to do is
loading WURFL data in memory and query for specific capabilities
you’re interested in for the currently requesting
browser/device. Let’s step into some more details for an ASP.NET Web
Forms application. (If you’re using ASP.NET
MVC, don’t panic—it’s exactly the same.)
Loading WURFL Data
WURFL data changes over time but it’s
not certainly real time data. So you can blissfully
load all of it at the startup of the application and keep it cached
for as long as you feel comfortable. When an update is
released, you just replace the data and restart the application. Both
programming and deployment aspects of the operation are
under your total control.
In an ASP.NET application, the Application_Start method is the
place where you perform all one-off initialization work. Here’s how you
can instruct the method
to load and cache WURFL data.
public class Global : HttpApplication
{
public const String WurflManagerCacheKey = "__WurflManager";
public const String WurflDataFilePath = "~/App_Data/wurfl-latest.zip";
public const String WurflManagerCacheKey = "__WurflManager";
public const String WurflDataFilePath = "~/App_Data/wurfl-latest.zip";
public const String WurflPatchFilePath
= "~/App_Data/web_browsers_patch.xml";
private void Application_Start(Object sender, EventArgs e)
{
var wurflDataFile = HttpContext.Current.Server.MapPath(WurflDataFilePath);
var wurflDataFile = HttpContext.Current.Server.MapPath(WurflDataFilePath);
var wurflPatchFile
=
HttpContext.Current.Server.MapPath(WurflPatchFilePath);
var configurer = new InMemoryConfigurer()
.MainFile(wurflDataFile)
.PatchFile(wurflPatchFile);
var manager
= WURFLManagerBuilder.Build(configurer);
HttpContext.Current.Cache[WurflManagerCacheKey] = manager;
}
}
You can specify multiple patch files by
simply calling the PatchFile method multiple times in the same chained expression.
var configurer
= new InMemoryConfigurer()
.MainFile(wurflDataFile)
.PatchFile(wurflPatchFile1)
.PatchFile(wurflPatchFile2);
As you can see, both file names and
cache details are under your control. You might want to
maintain a copy of the WURFL data on your Web server. The API doesn’t
currently support reading from other than local
files. You can also specify the WURFL data files in the web.config file. In this case, you
replace the call to InMemoryConfigurer with ApplicationConfigurer.
var configurer
= new ApplicationConfigurer();
The web.config section has to look like
below:
<wurfl>
<mainFile path="..." />
<patches>
<patch path="..." />
:
</patches>
</wurfl>
<patch path="..." />
:
</patches>
</wurfl>
Note that the <wurfl> section is a
user-defined section and needs be registered before use with the .NET
infrastructure. For this reason, you also need to add the following at
the top of the web.config file:
<br>&amp;lt;configuration&amp;gt;<br> &amp;lt;configSections&amp;gt;<br> &amp;lt;section name="wurfl" <br>type="WURFL.Config.WURFLConfigurationSection,wurfl" /&amp;gt;<br> &amp;lt;/configSections&amp;gt;<br> :<br>&amp;lt;/configuration&amp;gt;<br> Caching WURFL Data |
In Web applications, it is always a
good habit to cache any large and constant block of data;
WURFL data is no exception. To cache data in ASP.NET applications, you
typically use the native Cache object. WURFL doesn’t mandate any special guideline as far
as caching is
concerned. You are completely free of determining the name of the key
used to retrieve the data. Likewise, it is up to you to
implement caching and expiration policies. For example, you can make
cached WURFL data dependent on the timestamp of the
wurfl_latest.zip file
and/or patch files. In this way, cached data is
automatically cleared when you replace the WURFL file. For more
information on using cache dependencies in ASP.NET, have a look
at “Programming
ASP.NET 4”, Dino Esposito, Microsoft
Press.
To be precise, you never cache raw data
but you cache, instead, a reference to the object that
owns that data. The object you cache is the WURFL manager. This is
also the object you query for capabilities. Here’s how
you retrieve the cached instance of the manager.
var wurflManager
= HttpContext.Current.Cache[WurflManagerCacheKey]
as IWURFLManager;
It goes without saying that you should
check the instance for nullness as there’s no
guarantee that the reference is still there when you try to access it.
A good practice is checking whether the instance is null
and reload it as appropriate. Another alternative is not using the
(otherwise recommended) Cache object, but stick to the Application object which still keeps its content global to all sessions
but doesn’t implement any scavenging
policies.
Refactoring Your Code Just a Bit
You don’t actually need much code to
initialize WURFL; but this is not an excuse to keep
it quite simplistic. The sample applications for both ASP.NET Web
Forms and ASP.NET MVC use a helper class that encapsulate
much of the required logic and contain some additional features such
as auto-reload of WURFL data in case the ASP.NET cache is
cleared.
In particular, you might want to add
the WurflLoader.cs file
to your project and rewrite the startup code as follows:
private void Application_Start(Object sender, EventArgs e)
{
WurflLoader.Start();
}
The WurflLoader class has another static
method through which you retrieve the instance of the WURFL manager to
use for your queries. The method is GetManager and all it does is retrieving and returning the WURFL
manager instance from the
cache. If the instance is null, it then automatically creates and
caches new one. Here’s the source code:
public static IWURFLManager GetManager()
{
return GetManager(HttpContext.Current);
}
public static IWURFLManager GetManager(HttpContext context)
{
var wurflManager =
context.Cache[WurflManagerCacheKey] as IWURFLManager;
if (wurflManager ==
null)
return InitializeWurflManager(context, _wurflDataPath,
_wurflPatchFilePath);
return wurflManager;
}
The WurflLoader class is self-contained
and has no dependencies on other files, except the WURFL binaries.
Querying for Capabilities
Once you hold a WURFL Manager object in
your hands, you’re pretty much done. A WURFL
manager is an object that implements the IWURFLManager interface.
public interface IWURFLManager
{
IDevice GetDeviceForRequest(WURFLRequest wurflRequest);
IDevice GetDeviceForRequest(string userAgent);
IDevice GetDeviceForRequest(HttpRequest httpRequest);
IDevice GetDeviceForRequest(string userAgent);
IDevice GetDeviceForRequest(HttpRequest httpRequest);
IDevice GetDeviceById(string deviceId);
ICollection<IDevice> GetAllDevices();
}
The class offers a few methods for you
to gain access to the in-memory representation of the
detected device model. You can query for a device in a variety of
ways: passing the ASP.NET HttpRequest object, the user agent string, the device ID, or a WURFL
specific request
object. The WURFL specific request object —the class WURFLRequest—is merely an
aggregate of data that includes the user agent string and profile.
All of the methods on the WURFL manager
class return an IDevice object which represents the matched device model. The
interface has the following
structure:
public interface IDevice
{
string Id {
get; }
string UserAgent {
get; }
string GetCapability(string name);
IDictionary<string,
string>
GetCapabilities();
}
You can check the value of a specific
capability through the following code:
var is_tablet
= device.GetCapability("is_tablet");
If you call the GetCapabilities method
you get a dictionary of name/value pairs. The value associated with a
capability is always expressed as a string even when it
logically represents a number or a Boolean.
Armed with capabilities—WURFL supports
more than 500 different capabilities—you are
ready to apply the multi-serving pattern to your next ASP.NET mobile
Web site.
Summary
The WURFL API currently available for
ASP.NET is a rather generic one that works very closely to
the metal and doesn’t provide much abstraction. This is good news as
it allows developers to fully customize every single
aspect of their code interaction with WURFL. In particular, you can
control the caching logic and can easily define your
helper classes (like the aforementioned WurflLoader class) taking
into account testability and dependency injection.
No comments:
Post a Comment