WURFL InFuze Module for C# : User Guide

WURFL InFuze for C# is a C# module wrapping the WURFL C API. InFuze for C# exploits the performance of the InFuze C API inside your C# applications without having to write your own binding code.

Installing libwurfl

In order for the Module to work it is ESSENTIAL that the libwurfl library is installed on your system. libwurfl is provided in your Customer Vault/FileX.

If you have not already installed libwurfl, instructions can be found here. Release notes for each API can be found here.

To enable WURFL InFuze for C# on your application, you must download it from your File Manager.
The WurflInFuze.dll file must be added as a reference to any WURFL project, while the WurflInFuze.Aspnet.Extensions.dll file must be referenced only in ASP.NET projects where you plan to use WURFL InFuze for C#.
For example, you don't strictly need to reference WurflInFuze.Aspnet.Extensions.dll if you're using WURFL InFuze for C# from within a Console Application.

Warning: For installation on Windows, libwurfl v1.8.3.0 or greater is required.
Note: A .NET Framework of at least 4.5.2 is required for installation.

WURFL Data Snapshot

To perform lookups, you will need a copy of your WURFL data snapshot (also referred to as the wurfl.xml). While there is one included in the release package, it is intended to be a sample and will not contain all of your licensed capabilities. Your licensed WURFL data snapshot can be accessed by following these directions.

Getting Started

In the next sections we'll see a sample Console Application as well as an ASP.NET Web based application , using device detection and accessing WURFL static and virtual capabilities.

Console Application Usage

Here is an example Console Application to get started:

using WURFLInFuze;

namespace WURFLInFuzeSimpleTest
{
    class Program
    {
        static void Main(string[] args)
        {

Create the InMemoryConfigurer object setting the WURFL data file path;

            try
            {
                // before creating a Wurfl engine, we download an updated version of the wurfl file in the current directory
                // destination directory must be writable
                // replace this URL with your customer specific one, to avoid error 402
                WURFLManager.WurflDownload("https://data.scientiamobile.com/xxxxx/wurfl.zip", ".");

                InMemoryConfigurer configurer = new InMemoryConfigurer()
                    .MainFile("C:\\Program Files\\Scientiamobile\\InFuze\\wurfl.zip");

                IWURFLManager manager = null;

Create the WURFL Manager once, then lookup UserAgent and get the Device-Id, Static Capabilities and Virtual Capabilities required in your implementation (note that Virtual Capabilities are calculated at runtime).

                manager = WURFLManagerBuilder.Build(configurer);

                String ua = "Dalvik/1.6.0 (Linux; U; Android 4.3; SM-N900T Build/JSS15J)";

                IDevice device = manager.LookupUserAgent(ua);

                Console.WriteLine("Device : {0}", device.Id);

                String capName = "brand_name";
                Console.WriteLine("Static Capability {0}: {1}", capName, device.GetStaticCapability(capName));

                String vcapName = "is_android";
                Console.WriteLine("Virtual Capability {0}: {1}", vcapName, device.GetVirtualCapability(vcapName));

If you would like to look up a set of HTTP headers instead of a User-Agent (for example to look up requests with User-Agent Client Hints), you can use LookupHeaders instead of LookupUserAgent as shown below.

                manager = WURFLManagerBuilder.Build(configurer);

                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("User-Agent", "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Mobile Safari/537.36");
                headers.Add("Sec-Ch-Ua", "\"Chromium\";v=\"94\", \"HuaweiBrowser\";v=\"99\", \";Not A Brand\";v=\"99\"");
                headers.Add("Sec-Ch-Ua-Full-Version", "99.123.456");
                headers.Add("Sec-Ch-Ua-Platform", "Android");
                headers.Add("Sec-Ch-Ua-Platform-Version", "12");
                headers.Add("Sec-Ch-Ua-Model", "Pixel 6");

                IDevice device = manager.LookupHeaders(headers);

                Console.WriteLine("Device : {0}", device.Id);

                String capName = "brand_name";
                Console.WriteLine("Static Capability {0}: {1}", capName, device.GetStaticCapability(capName));

                String vcapName = "is_android";
                Console.WriteLine("Virtual Capability {0}: {1}", vcapName, device.GetVirtualCapability(vcapName));

You can even ask the device instance for the full list of its Static and Virtual Capabilities as well as its names and values.

                Console.WriteLine("--- Device Static Capabilities ---");
                foreach (KeyValuePair<string, string> dCap in device.GetCapabilities())
                    Console.WriteLine("[{0}] = [{1}]", dCap.Key, dCap.Value);

                Console.WriteLine("--- Device Virtual Capabilities ---");
                foreach (KeyValuePair<string, string> vCap in device.GetVirtualCapabilities())
                    Console.WriteLine("[{0}] = [{1}]", vCap.Key, vCap.Value);

Dispose the device object when you don't need it anymore. This is necessary to release allocated resources for that instance on the WURFL C API side. It sets the C# instance as disposable for the garbage collector.

                device.Dispose();

Dispose the manager object when you don't need it anymore. As for the IDevice object, it is necessary to release allocated resources on the WURFL C API side.

                manager.Dispose();
            }

WURFL will throw a WURFLException in the case of failure throughout the entire process

            catch (WURFLException e)
            {
                Console.WriteLine("WURFL throws this exception : {0}", e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("System throws this exception : {0} - {1}", e.GetType(), e.Message);
            }
        }
    }
}

Static Capability filtering

In order to reduce memory usage and increase performance, you can specify a subset of the 500+ WURFL static capabilities that will be held by the WURFL Manager object.

You can set capability filters as follows:

configurer.SelectCapabilities(new String[] { "device_os", "is_tablet" });

Note: In this case you will be able to access only the device_os and is_tablet Static Capability values of detected devices. Looking for unfiltered Static Capabilities will return empty strings.

WURFL Cache

In order to increase performance while processing real HTTP traffic, we suggest setting up an LRU cache. The LRU caching strategy will speed up lookup operations on User Agents that have already been processed by keeping them in a Least Recently Used map. By default the cache will be set to 30000 entries which accounts for 7 to 10 MB of additional memory usage. Users are advised to size their cache generously (100,000 or more) to increase performance. For more information, please see LRU Cache Mechanism

If you want to modify the cache size, you can do it in the InMemoryConfigurer object:

configurer.SetCacheSize(100000);

If you want to disable the cache feature:

configurer.DisableCache();

WURFL Updater

If you want to keep your wurfl.zip uptodate with Scientiamobile's data release schedule, then you might want to use the Updater feature.

To configure the Updater you need your personal updater url taken from Scientiamobile Customer Vault. You may configure the periodicity (frequency) you would like for update checks, choosing from two values: Daily and Weekly (the default value is Daily). Use UpdaterSetLogPath to set updater log path where you will find detailed logs on Updater activity Do note that a wurfl.zip file must already be present in a writable path in order for the updater to check the file and determine whether or not it needs to update the file.

There are to ways to configure the WURFL Updater:

  • using IWURFLManager instance methods:
manager.UpdaterSetDataUrl("https://data.scientiamobile.com/xxxxx/wurfl.zip");
manager.UpdaterSetDataFrequency(WurflUpdaterFrequency.WURFL_UPDATER_FREQ_DAILY);
//manager.UpdaterSetDataFrequency(WurflUpdaterFrequency.WURFL_UPDATER_FREQ_WEEKLY);
manager.UpdaterSetLogPath("C:\\Temp\\updater.log");
// start the updater explicitly
manager.UpdaterStart();
  • using InMemoryConfigurer object:
configurer.UpdaterUrl("https://data.scientiamobile.com/xxxxx/wurfl.zip");
configurer.UpdaterFrequency(WurflUpdaterFrequency.WURFL_UPDATER_FREQ_DAILY);
//configurer.UpdaterFrequency(WurflUpdaterFrequency.WURFL_UPDATER_FREQ_WEEKLY);
configurer.UpdaterLogpath("C:\\Temp\\updater.log");

Note: When using the InMemoryConfigurer object, you don't need to explicitly start the Updater. It will be done automatically when the IWURFLManager instance is created.

ASP.NET Web Application Usage

In your ASP.NET project, add the WurflInFuze.dll and WurflInFuze.Aspnet.Extensions.dll files as a reference.

In your App_Code folder create a class WurflSampleASPNETApp which will hold the WURFL manager instance used for lookups.

using WURFL;

public static class WurflSampleASPNETApp
{
    public static IWURFLManager WurflManager;
}

In an ASP.NET Web application, the Application_Start method in your Global.asax file is the place where all one-off initializations will be performed. Here you can instruct the method to initialize the WurflManager instance.

  .
  .
<%@ Import Namespace="WURFLInFuze" %>
<%@ Import Namespace="WURFLInFuze.Aspnet.Extensions.Config" %>
  .
  .
  .
  .

  private void Application_Start(Object sender, EventArgs e)
  {
    try
    {
        WurflSampleASPNETApp.WurflManager = WURFLManagerBuilder.Build(new ApplicationConfigurer());
    }
    catch (Exception ex)
    {
        HttpRuntime.UnloadAppDomain();
        initializationError = ex;
    }
  }
  .
  .
  .
  .

The WURFL configuration should be placed in your web.config file, adding the following directives:

<wurfl>
   <mainFile path="~/App_Data/wurfl.zip" />
</wurfl>

This instructs the WurflSampleASPNETApp.WurflManager initialization to look for the wurfl.zip file in your application's App_Data folder.

The <wurfl> section is user-defined and needs to be registered before use. For this reason, you also need to add the following at the top of your web.config file:

<configuration>
  <configSections>
     <section name="wurfl" type="WURFLInFuze.Aspnet.Extensions.Config.WURFLConfigurationSection, WurflInFuze.Aspnet.Extensions, Version=1.9.5.0, Culture=neutral, PublicKeyToken=816aeec277aa13b9"/>
  </configSections>
  :
</configuration>

With the WURFL Manager object instantiated by Application_Start, you are ready to lookup Useragent/Request.

To perform a lookup during your Default.aspx page loading, place the following code in ìts CodeBehind (the Default.aspx.cs file)

  .
  .
  using WURFLInFuze;
  using WURFLInFuze.Aspnet.Extensions.Config;
  .
  .
  public partial class _Default : System.Web.UI.Page
  {
    public IDevice wurflDevice;
    public String wurflDeviceId;
    public String wurflDeviceBrandName;
    public String wurflDeviceIsAndroid;

    protected void Page_Load(object sender, EventArgs e)
    {
        /**
         * on page load we populate wurflDevice and wurflDeviceId with wurfl detection results
         **/
        wurflDevice = WurflSampleASPNETApp.WurflManager.LookupRequest(Request);
        wurflDeviceId = wurflDevice.Id;
        wurflDeviceBrandName = wurflDevice.GetStaticCapability("brand_name");
        wurflDeviceIsAndroid = wurflDevice.GetVirtualCapability("is_android");
    }
  }
  .
  .

Note: You can lookup devices either by passing the whole HttpRequest or the simple User-Agent.
In this last case, you may use the following code

        wurflDevice = WurflSampleASPNETApp.WurflManager.LookupUserAgent(Request.UserAgent);

Note: Using the whole HttpRequest will result in a more precise device lookup

Now you can show the lookup result in your Default.aspx file

  .
  .
  <body>
      <form id="form1" runat="server">
          <div>
              WURFL device Id = <%= wurflDeviceId %> <br/>
              WURFL device Brand Name = <%= wurflDeviceBrandName %> <br/>
              WURFL device Is Android = <%= wurflDeviceIsAndroid %> <br/>
          </div>
      </form>
   </body>
  .
  .

You can lookup devices either by passing a plain User-Agent String.

The value associated with a capability (static or virtual) is always expressed as a string, even when it logically represents a number or a Boolean.

Don't forget to Dispose the IDevice and IWURFLManager instances when you don't need them anymore.

Static Capability filtering

In order to reduce memory usage and increase performance, you can specify a subset of the 500+ WURFL static capabilities that will be held by the WURFL manager object.

You can set capability filters in your web.config as follows:

<wurfl>
    <mainFile path="~/App_Data/wurfl.zip" />
    <filter caps="resolution_width,is_smarttv" />
</wurfl>

Note: In this case you will be able to access only the device_os and is_tablet Static Capabilities values of the detected devices. Looking for unfiltered Static Capabilities will return an empty string.

WURFL Cache

In order to increase performance while processing real HTTP traffic, we suggest setting up an LRU cache. The LRU caching strategy will speed up lookup operations on User Agents that have already been processed by keeping them in a Least Recently Used map. By default the cache will be set to 30000 entries which accounts for 7 to 10 MB of additional memory usage. Specific concerns regarding memory usage apart, users are advised to size their cache generously (100,000 or more) to increase performance. For more information, please see LRU Cache Mechanism

If you want to modify the cache size, you can do it in InMemoryConfigurer object:

<wurfl cachesizeua="100000">
    .
    .
</wurfl>

If you want to disable the cache feature:

<wurfl usecache="false">
    .
    .
</wurfl>

WURFL Updater

If you want to keep your wurfl.zip uptodate with Scientiamobile's data release schedule, you should consider using the WURFL Updater.

To configure the Updater you need your personal updater url taken from the Scientiamobile Customer Vault. You may configure the periodicity (frequency) you would like for update checks, choosing from two values: Daily and Weekly (the default value is Daily). Use logpath to set updater log path where you will find detailed logs about the updater activity

<wurfl>
    <mainFile path="~/App_Data/wurfl.zip" />
    <updater url="https://data.scientiamobile.com/xxxxx/wurfl.zip" frequency="WURFL_UPDATER_FREQ_DAILY" logpath="~/App_Data/updater.log"/>
</wurfl>

The frequency and logpath parameters are not mandatory.

IMPORTANT - Decommissioning of WurflMatchMode options

Prior to version 1.9 of the API, users could choose between WurflMatchMode.Performance and WurflMatchMode.Accuracy engine optimization options. These options had been introduced years ago to manage the behavior of certain web browsers and their tendency to present "always different" User-Agent strings that would baffle strategies to cache similar WURFL queries in memory.
As the problem has been solved by browser vendors, the need to adopt this strategy has diminished and ultimately disappeared (i.e. there was no longer much to be gained with the performance mode in most circumstances) and ScientiaMobile elected to "remove" this option to simplify configuration and go in the direction of uniform API behavior in different contexts.

Customers who may find themselves in the unlikely situation of having to analyze significant amounts of legacy web traffic, may still enable the old WurflMatchMode.Performance behavior by set WurflMatchMode.FastDesktopBrowserMatch in their configuration.

Please note that users with the old WurflMatchMode.Performance target engine will not receive an error.
The old behavior will not be triggered, though. The WurflMatchMode.Default target (corresponding to the old WurflMatchMode.Accuracy) will be used instead.


© 2024 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.