Note: This guide assumes that you have access to a running instance of the WURFL Microservice HTTP Server, either through ScientiaMobile's Docker Registry, the AWS Marketplace, the Azure Marketplace, or other distribution channels. The guide also assumes familiarity with Device Detection (WURFL) and WURFL Capabilities.
WURFL Capabilities: WURFL capabilities are device properties represented in WURFL. While users of the WURFL Microservice for Docker have access to the list of licensed capabilities, customers who obtained the product through one of the Marketplace will have access to the WURFL capability list, predefined for the product they have licensed. Please note that there are two types of capabilities supported in WURFL: Static and Virtual.
While the difference between the two is mostly immaterial for you as a user as far as their practical usage goes, you still need to use two separate methods to use one or the other.
WURFL Microservice Client API (wmclient
): Given an HTTP Request and a capability, the WURFL Client API will return the property value.
Note: While the
wmclient
is an API, it requires interaction with the WURFL Microservice server to work. This introduces some latency (hugely mitigated by a built-in caching layer). For this reason, ScientiaMobile does not refer to the WURFL Microservice Client (wmclient
) as a "WURFL API". That name is reserved for the WURFL OnSite APIs.
wmclient
APIIn order to use the wmclient
API please follow these instructions:
Ensure the properly SDK are installed on your machine.
Get the package ScientiaMobile.Wurfl.Microservice.Client from NuGet
Open your solution in your preferred IDE (tested with Visual Studio 2022)
Add a reference to wmclient.dll through the 'Add Reference' menu
Code your application following the example in the Code example section below.
You may also find a working example in the Example folder of our public GitHub repository.
If you want to contribute to the project, please follow the guidelines below.
Visit our public GitHub repository for the WURFL Microservice .NET client
Fork the repository to your GitHub account
Create a new branch for your feature or bugfix
Make your changes and commit them with clear, descriptive messages
Push your branch to your forked repository
Open a Pull Request (PR) against the main repository
Our team will review your contribution and provide feedback
using System;
using System.Collections.Generic;
using Wmclient;
namespace Example
{
public class WmClientExample
{
static void Main(string[] args)
{
try
{
// First we need to create a WM client instance, to connect to our WM server API at the specified host and port.
// Last parameter is a prefix for path, most of the time we won't need it
WmClient client = WmClient.Create("http" , "localhost", "8080", "");
if (client != null)
{
// enable cache: by setting the cache size we are also activating the caching option in WM client.
// In order to not use cache, you just to need to omit setCacheSize call
client.SetCacheSize(100000);
// We ask Wm server API for some Wm server info such as server API version and info about WURFL API and file used by WM server.
JSONInfoData info = client.GetInfo();
Console.WriteLine("Server info: \n");
Console.WriteLine("WURFL API version: " + info.Wurfl_api_version);
Console.WriteLine("WM server version: " + info.Wm_version);
Console.WriteLine("WURFL file info:" + info.Wurfl_info + '\n');
var requestedStaticCaps = new string[]{
"brand_name",
"model_name"
};
var requestedVirtualCapabilities = new string[]{
"is_smartphone",
"form_factor"
};
// set the capabilities we want to receive from WM server
client.SetRequestedStaticCapabilities(requestedStaticCaps);
client.SetRequestedVirtualCapabilities(requestedVirtualCapabilities);
//var ua = "UCWEB/2.0 (Java; U; MIDP-2.0; Nokia203/20.37) U2/1.0.0 UCBrowser/8.7.0.218 U2/1.0.0 Mobile";
//Console.WriteLine("Device lookup for user-agent: " + ua);
// Perform a device detection calling WM server API passing the user-agent
// JSONDeviceData device = client.LookupUserAgent(ua);
var headers = new Dictionary<String, String>();
headers.Add("Content-Type", "application/json");
headers.Add("Accept-Encoding", "gzip, deflate");
headers.Add("Accept-Language", "en");
headers.Add("Referer", "https://www.cram.com/flashcards/labor-and-delivery-questions-889210");
headers.Add("User-Agent", "Opera/9.80 (Android; Opera Mini/51.0.2254/184.121; U; en) Presto/2.12.423 Version/12.16");
headers.Add("X-Clacks-Overhead", "GNU ph");
headers.Add("X-Forwarded-For", "110.54.224.195, 82.145.210.235");
headers.Add("X-Operamini-Features", "advanced, camera, download, file_system, folding, httpping, pingback, routing, touch, viewport");
headers.Add("X-Operamini-Phone", "Android #");
headers.Add("X-Operamini-Phone-Ua", "Mozilla/5.0 (Linux; Android 8.1.0; SM-J610G Build/M1AJQ; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36");
headers.Add("Accept", "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1");
headers.Add("Device-Stock-Ua", "Mozilla/5.0 (Linux; Android 8.1.0; SM-J610G Build/M1AJQ; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/69.0.3497.100 Mobile Safari/537.36");
headers.Add("Forwarded", "for=\"110.54.224.195:36350\"");
// Perform a device detection calling WM server API passing the whole request headers
JSONDeviceData device = client.LookupHeaders(headers);
// Let's get the device capabilities and print some of them
Console.WriteLine("Detected device WURFL ID: " + device.Capabilities["wurfl_id"]);
Console.WriteLine("Detected device brand & model: " + device.Capabilities["brand_name"]
+ " " + device.Capabilities["model_name"]);
Console.WriteLine("Detected device form factor: " + device.Capabilities["form_factor"]);
if (device.Capabilities["is_smartphone"].Equals("true"))
{
Console.WriteLine("This is a smartphone");
}
// Now let's print all the device capabilities
DumpDevice(device);
// Get all the device manufacturers, and print the first twenty
int limit = 20;
String[] deviceMakes = client.GetAllDeviceMakes();
Console.WriteLine(String.Format("Print the first {0} Brand of {1}\n", limit, deviceMakes.Length));
// Sort the device manufacturer names
Array.Sort(deviceMakes);
for (int i = 0; i < limit; i++)
{
Console.WriteLine(String.Format(" - {0}\n", deviceMakes[i]));
}
// Now call the WM server to get all device model and marketing names produced by Apple
Console.WriteLine("Print all Model for the Apple Brand");
JSONModelMktName[] devNames = client.GetAllDevicesForMake("Apple");
// Sort ModelMktName objects by their model name (a specific comparer is used)
Array.Sort(devNames, new ByModelNameComparer());
foreach (JSONModelMktName modelMktName in devNames)
{
Console.WriteLine(" - {0} {1}\n", modelMktName.Model_Name, modelMktName.Marketing_Name);
}
// Now call the WM server to get all operative system names
Console.WriteLine("Print the list of OSes");
String[] oses = client.GetAllOSes();
// Sort and print all OS names
Array.Sort(oses);
foreach (String os in oses)
{
Console.WriteLine(String.Format(" - {0}\n", os));
}
// Let's call the WM server to get all version of the Android OS
Console.WriteLine("Print all versions for the Android OS");
String[] osVersions = client.GetAllVersionsForOS("Android");
// Sort all Android version numbers and print them.
Array.Sort(osVersions);
foreach (String ver in osVersions)
{
Console.WriteLine(" - {0}\n", ver);
}
}
else
{
Console.WriteLine("WmClient instance is null");
}
// Deallocate all client resources. Any call on client method after this one will throw a WmException
client.DestroyConnection();
}
catch (WmException e)
{
// problems such as network errors or internal server problems
Console.WriteLine(e.Message);
}
finally
{
Console.Write("Press a key...");
Console.ReadKey();
}
}
// Prints all the device capabilities
private static void DumpDevice(JSONDeviceData device)
{
if(device.Capabilities.Count > 0)
{
Console.WriteLine("Requested device capabilities");
Console.WriteLine();
var capKeys = device.Capabilities.Keys;
foreach(string key in capKeys)
{
Console.WriteLine("Capability " + key + ": " + device.Capabilities[key]);
}
}
}
}
// Comparer implementation used to sort JSONModelMktName objects according to their model name property,
// for which is used the String natural ordering.
internal class ByModelNameComparer : IComparer<JSONModelMktName>
{
public int Compare(JSONModelMktName o1, JSONModelMktName o2)
{
if (o1 == null && o2 == null) { return 0; }
if (o1 == null && o2 != null)
{
return 1;
}
if (o1 != null && o2 == null)
{
return -1;
}
return o1.Model_Name.CompareTo(o2.Model_Name);
}
}
}
If you are using device detection from code running as part of an HTTP server, it is highly recommended that you pass the complete HttpRequest
object to the LookupRequest
method as follows:
JSONDeviceData device = client.LookupRequest(request);
This will provide optimal detection accuracy (see examples/web.php
). For a complete reference of all static and virtual capabilities, you can refer to this document. Please note that WURFL Microservice for the AWS Marketplace comes with a predefined set of capabilities.
WmClient Class exposes the following members:
Properties
Name | Description |
---|---|
Host |
The WM server host to connect to. |
MakeModels |
|
Port |
Port of the host to connect to. |
StaticCaps |
|
VirtualCaps |
Top Methods
Name | Description |
---|---|
Create |
Creates a WURFL private cloud client and tests if server denoted by the given host and port is available for connection. Throws WmClientException in case server is down or not available for connection. |
DestroyConnection |
Diposes all internal resources used (ie: the instance of HttpClient). Calling API methods. |
GetApiVersion |
Returns the current client version. |
GetInfo |
Returns information about the running WM server and API. Throws WmClientException in case any client related problem occurs. |
HasStaticCapability(string capName) |
Returns true if the given capName exist in this client' staticcapability set, false otherwise. |
HasVirtualCapability(string capName) |
Returns,true if the given capName exist in this client' virtual capability set, false otherwise. |
LookupDeviceID(string wurfl_id) |
Searches WURFL device data using the given WURFL device id for detection. Throws WmClientException in case any client related problem occurs. |
LookupRequest(HttpRequest req) |
Searches WURFL device data using the given HttpRequest headers for detection. Throws WmClientException in case any client related problem occurs. |
LookupUserAgent(string userAgent) |
Searches WURFL device data using the given user-agent for detection. Throws WmClientException in case any client related problem occurs. |
SetCacheSize(int size) |
Set the client internal cache maximum size. |
SetRequestedStaticCapabilities(string[] caps) |
Sets the list of static capabilities to be requested to WM server. |
SetRequestedVirtualCapabilities(string[] vcaps) |
Sets the list of virtual capabilities to be requested to WM server. |
GetAllDeviceMakes |
Returns a list of all device manufacturers. Throws WmClientException in case any client related problem occurs |
GetAllDevicesForMake(string make) |
Returns a list of all devices for the given manufacturer. Throws WmClientException in case any client related problem occurs |
GetAllOSes() |
Returns a list of all device OSes. Throws WmClientException in case any client related problem occurs. |
GetAllVersionsForOS(string osName) |
Returns all OS versions for the given OS name. Throws WmClientException in case any client related problem occurs. |
JSONDeviceData Class holds the detected device data received from WM server
JSONDeviceData type exposes the following members:
Constructors
Name | Description |
---|---|
APIVersion |
Returns the API version. |
Capabilities |
List of the capability values for the detected device. |
Error |
Returns a message if any error occurred during device detection, or an empty string if detection task returned a correct result. |
Ltime |
Time of the WURFL.xml last load on server |
Mtime |
This objects's generation time |
JSONInfoData Class holds informations about wurfl private cloud server and API.
JSONInfoData type exposes the following members:
Constructors
Name | Description |
---|---|
Ltime |
Time of the WURFL.xml last load on server |
Static_caps |
List of static capabilities supported by currently running server |
Virtual_caps |
List of virtual capabilities supported by currently running server |
Wm_version |
Version of the WM server |
Wurfl_api_version |
Version of WURFL API used by the WM server |
Wurfl_info |
Information about the WURFL file used by the WM server |
JSONMakeModel Class models simple device "identity" data in JSON format.
JSONMakeModel type exposes the following members:
Constructors
Name | Description |
---|---|
JSONMakeModel |
Top Properties
Name | Description |
---|---|
Brand_Name |
Value of the WURFL capability brand_name |
Marketing_Name |
Value of the WURFL capability marketing_name |
Model_Name |
Value of the WURFL capability model_name |
WmException Class is a general purpose exception thrown whenever an unrecoverable error occurs during device detection (ie: no connection available to WM server, wrong url or port configurations, etc.
Constructors
Name | Description |
---|---|
WmException(String) | Creates a WmClientException with the given error message. |
WmException(String, Exception) | Creates a WmException with the given error message and the exception that caused the current one. (ie: if uri is invalid, innerException could be an UriSyntaxException). |
Error in case of Missing Capabilities
As mentioned above, depending on the configuration of your WURFL Microservice, one or more WURFL capabilities may be unavailable. In this case, the JSONDeviceData.Capabilities
dictionary will not contain an entry for those capabilities and the caller will get a KeyNotFoundException
. To avoid KeyNotFoundException
you must verify the presence of the capability before retrieving it.
Presence of a capability can be checked with:
if(JSONDeviceData.Capabilities.ContainsKey("has_cellular_radio") {
value = JSONDeviceData.capabilities["has_cellular_radio"];
}
Another option is to use method:
string value;
if (JSONDeviceData.capabilities.TryGetValue("has_cellular_radio", out value))
{
// Do something with value value
}
Additional capabilities can always be obtained by upgrading to greater version of the AMIs in the AWS Marketplace or by contacting ScientiaMobile to license additional capabilities for the Docker Image or other products.
© 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.