ScientiaMobile WURFL Cloud Client for ASP.NET

Introduction

The WURFL Cloud Service by ScientiaMobile, Inc., is a cloud-based mobile device detection service that can quickly and accurately detect over 500 capabilities of visiting devices. It can differentiate between portable mobile devices, desktop devices, SmartTVs and any other types of devices that have a web browser.

In order to use the WURFL Cloud client you need to obtain an API key from Scientiamobile. The WURFL Cloud API is offered in two main flavors - Base and Premium. The Base version is limited to returning only a small number of capabilities; the Premium version doesn't have an upper limit to the number of returned capabilities and also offers more caching options for improving the overall performance. Once you've properly set up an account, you can download the cloud client and receive an API key to successfully use the library. You can create an account by visiting ScientiaMobile.com.

Overviewing the Library

The public interface of the WURFL Cloud API is fairly simple and consists of a single class - the CloudClientManager class. As a developer, you only need to get familiar with the members of this class. Table 1 provides a list of the public members.

The library is made of a single assembly named ScientiaMobile.WurflCloud. The library has no dependencies on external assemblies and requires the .NET Framework 4.0.

Member Description
GetApiVersion Gets a string with the version number of the WURFL cloud server API.
Note: You're not directly exposed to this API, but knowing its version number can be useful for tracking down possible problems.
GetCachingModuleName Gets a string with the fully qualified name of the .NET class that the WURFL cloud ASP.NET API uses to cache server responses.
Note: This member is relevant for Premium users only.
GetClientVersion Gets a string with the version number of the WURFL cloud ASP.NET client API.
GetDeviceInfo Returns the values of the capabilities available for the requesting device or user-agent string.
Note: The capabilities returned depend on the account level.
SetCache Allows replacing the default cache module that the ASP.NET client API will use to improve performance.
Note: This member is only available to Premium users. The default cache module uses the ASP.NET Cache. Third-party developers can create additional cache modules by simply implementing the IWurflCloudCache interface.

Before you can start using the CloudClientManager class, you should initialize it by providing a valid API key and optionally a caching module. You stuff this information in an instance of the CloudClientConfig class. The library offers a default configuration object through the class DefaultCloudClientConfig class. Most of the time, all you need to do is getting a new instance of this class and set your API key, as shown below:

    var config = new DefaultCloudClientConfig
                    {
                        ApiKey = "123456:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
                    };
    var manager = new CloudClientManager(config);

The API Key is used to authenticate with the WURFL Cloud Service. It can be found at in your account at ScientiaMobile.com.

Table 2 lists the public members of the CloudClientConfig class.

TABLE 2 - Public members of the CloudClientConfig class.

Member Description
ApiKey Gets and sets the API key that identifies your developer account.
Note: The API Key is 39 characters in with the format: n:x where 'n' is a 6-digit number and 'x' is a 32-char alphanumeric sequence.
Compression Indicates whether GZIP compression is required from cloud server. Compression is disabled by default.
Note: Regardless of the value of this setting the requesting device will always receive uncompressed data.

The constructor of the CloudClientManager also sets up an intermediate cache where server responses are stored for a better performance.

The Caching Layer

The ASP.NET cloud API sits in between your ASP.NET application and the WURFL cloud. It tracks all of your requests and caches frequently requested devices. The Base library doesn't let you replace the built-in caching mechanism. The Premium library, instead, provides full control over the caching infrastructure. Table 3 lists the currently supported caching modules.

TABLE 3 - Caching modules available in the ASP.NET WURFL client API.

Caching Module Description
CookieWurflCloudCache Uses a cookie to store the value of returned capabilities. This is the only caching mechanism supported in the Base library.
Note: Given the limited size of cookies, this caching module is not recommended in applications based on the Premium library. The size of the server response for a large number of capabilities may exceed the maximum cookie size set by the browser.
MemoryWurflCloudCache Server responses are cached in the ASP.NET Cache object. The cached data has no dependencies and expires automatically if not used for 20 minutes.
Note: This module is only supported in the Premium library.
NoWurflCloudCache No caching layer is used and every request to the ASP.NET WURFL cloud client results in a request to the server cloud.
Note: This module is only supported in the Premium library.

The cache API is designed to be pluggable. A valid cache module is any class that implements the IWurflCloudCache interface. For your convenience, the API also provides a half-done cache provider class - the WurflCloudCacheBase class. The most quick and simple way to create a custom cache module is deriving a new class from WurflCloudCacheBase. Here's an example that binds the response for any requested user agent string to a helper cache entry. By invalidating the helper cache entry, you can clear all cached data in a single shot.

    public class FlexibleMemoryWurflCloudCache : WurflCloudCacheBase
    {
        private const String PurgeKey = "Wurfl_Cloud_Purge_Key";
        private readonly System.Web.Caching.Cache _cache;
        private readonly Int32 _durationInSeconds;

        public FlexibleMemoryWurflCloudCache(Int32 durationInSeconds = 1200)
        {
            _durationInSeconds = durationInSeconds;
            _cache = HttpContext.Current.Cache;
            _cache[PurgeKey] = DateTime.Now;
        }

        #region Overrides
        public override DeviceInfo GetDevice(HttpContextBase context)
        {
            if (context == null)
                return new DeviceInfo();

            // User agent strings are hashed to produce shorter keys for the cache.
            var userAgent = context.Request.UserAgent ?? String.Empty;

            // Attempts to read from the cache
            var device = ReadFromCache(userAgent);
            return device ?? new DeviceInfo();
        }

        public override DeviceInfo GetDevice(String userAgent)
        {
            if (String.IsNullOrEmpty(userAgent))
                return new DeviceInfo();

            // Attempts to read from the cache
            var device = ReadFromCache(userAgent);
            return device ?? new DeviceInfo();
        }

        public override Boolean SetDevice(HttpContextBase context, DeviceInfo device)
        {
            if (device == null)
                return false;
            if (context == null)
                return false;
            // User agent strings are hashed to produce shorter keys for the cache.
            var userAgent = context.Request.UserAgent ?? String.Empty;
            WriteToCache(userAgent, device);
            return true;
        }

        public override Boolean SetDevice(String userAgent, DeviceInfo device)
        {
            if (device == null)
                return false;
            if (String.IsNullOrEmpty(userAgent))
                return false;

            // User agent strings are hashed to produce shorter keys for the cache.
            WriteToCache(userAgent, device);
            return true;
        }

        public override Boolean Purge()
        {
            _cache[PurgeKey] = DateTime.Now;
                return true;
        }

        public override void Close()
        {
        }
        #endregion

        #region Helpers
        private static String HashUserAgentString(String userAgent)
        {
            return HashHelper.GetHash(userAgent);
        }

        private DeviceInfo ReadFromCache(string userAgent)
        {
            var uaHash = HashUserAgentString(userAgent);
            return _cache[uaHash] as DeviceInfo;
        }

        private void WriteToCache(String userAgent, DeviceInfo device)
        {
            var uaHash = HashUserAgentString(userAgent);
            _cache.Insert(uaHash, device,
                new CacheDependency(null, new[] { PurgeKey }),
                System.Web.Caching.Cache.NoAbsoluteExpiration,
                TimeSpan.FromSeconds(_durationInSeconds));
        }
        #endregion
    }

To force the WURFL cloud client API to use a custom caching module, you proceed as follows:

    var config = new DefaultCloudClientConfig
                {
                    ApiKey = "123456:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
                };
    var cacheModule = new FlexibleMemoryWurflCloudCache()
    var manager = new CloudClientManager(config).SetCache(cacheModule);

If you're going to use the WURFL cloud client API within an ASP.NET application, you might want to create your own ASP.NET Cache based provider or, why not, a provider that uses the AppFabric Caching infrastructure.

Querying The Cloud Client API

To query the WURFL database in the cloud, you use the GetDeviceInfo method on the CloudClientManager class. The method has a few overloads:

public DeviceInfo GetDeviceInfo(HttpContextBase context) public DeviceInfo GetDeviceInfo(HttpContextBase context, String[] capabilities) public DeviceInfo GetDeviceInfo(WurflCloudRequest request) public DeviceInfo GetDeviceInfo(WurflCloudRequest request, String[] capabilities)

All methods return a DeviceInfo object. Table 4 lists the public properties of DeviceInfo.

TABLE 4 - Public interface of the DeviceInfo class.

Members Description
Capabilities Name/value dictionary of capabilities as returned by the server.
Errors Name/value dictionary of errors as returned by the server.
Get Method that takes a capability name and returns the corresponding value as a string.
Id ID of the device corresponding to the user agent string as identified by the WURFL server engine.
ResponseOrigin Indicates the source of the response. Possible values come from the ResponseType enumeration: None, Cloud, Cache.
ServerVersion Version of the WURFL server API.
WurflLastUpdate Date the WURFL database was last updated on the server.

Let's find out more detail.

    DeviceInfo GetDeviceInfo(HttpContextBase context)

This method identifies the requesting device from the information in the HTTP request and places a request to the cloud client for all capabilities currently associated with the account.

    DeviceInfo GetDeviceInfo(HttpContextBase context, String[] capabilities)

The method identifies the requesting device from the information in the HTTP request and places a request to the cloud client for the specified capabilities. If some of the specified capabilities can't be retrieved an empty string is returned along with an entry in Errors dictionary of the DeviceInfo object.

    DeviceInfo GetDeviceInfo(WurflCloudRequest request)

The method identifies the requesting device from the information in the custom request object. You use this method when you intend to test the capabilities associated with a given combination of HTTP headers and user agent. As no specific set of capabilities is specified, the method returns all capabilities associated with the account.

    DeviceInfo GetDeviceInfo(WurflCloudRequest request, String[] capabilities)

The method identifies the requesting device from the information in the custom request object and returns the specified capabilities if possible.

You should note that any requests may be resolved from the ASP.NET cloud cache or by placing a request to the cloud server.

Building a Sample ASP.NET Site

The following code shows how to retrieve the capabilities associated with the requesting device. You can imagine this code being called from within an ASP.NET controller (if ASP.NET MVC is used) or from within an ASPX page.

    public DeviceInfoViewModel GetDataByRequest(HttpContext context)
    {
        var config = new DefaultCloudClientConfig
        {
            ApiKey = "123456:xxxxxxxxxxxxxxxxxxxxxxxxxx"
        };

    var manager = new CloudClientManager(config);
    var info = manager.GetDeviceInfo(context, new[] { "is_wireless_device", "model_name" });
    var model = new DeviceInfoViewModel
                {
                    DeviceId = info.Id,
                    ServerVersion = info.ServerVersion,
                    DateOfRequest = info.WurflLastUpdate.ToString(),
                    Library = manager.GetClientVersion(),
                    Capabilities = info.Capabilities,
                    Errors = info.Errors,
                    Source = info.ResponseOrigin
                };
        return model;
    }

The DeviceInfoViewModel is a helper class that gathers information from the WURFL cloud client API and makes it ready for display. You can directly check a capability as below:

    var isMobileAsText = info.Get("is_wireless_device"); // Returns a string!

If you want to test capabilities starting from a user agent string, you proceed as follows:

    var ua = "apple iphone";
    var manager = new CloudClientManager(config);
    var wurflRequest = new WurflCloudRequest(context) {UserAgent = ua};
    var info = manager.GetDeviceInfo(context, new[] { "is_wireless_device", "model_name" });

© 2025 ScientiaMobile Inc.
All Rights Reserved.

NOTICE: All information contained herein is, and remains the property of ScientiaMobile Incorporated and its suppliers, if any. The intellectual and technical concepts contained herein are proprietary to ScientiaMobile Incorporated and its suppliers and may be covered by U.S. and Foreign Patents, patents in process, and are protected by trade secret or copyright law. Dissemination of this information or reproduction of this material is strictly forbidden unless prior written permission is obtained from ScientiaMobile Incorporated.