\r\n

51Degrees Device Detection .NET  4.3

Device detection services for 51Degrees Pipeline

AspNetCore2.1/Startup.cs

This example shows how to integrate the Pipeline API with a device detection engine into an ASP.NET Core web app.The source code for this example is available in full on GitHub.

This example can be configured to use the 51Degrees cloud service or a local data file. If you don't already have data file you can obtain one from the device-detection-data GitHub repository.

To use the cloud service you will need to create a resource key. The resource key is used as short-hand to store the particular set of properties you are interested in as well as any associated license keys that entitle you to increased request limits and/or paid-for properties.

You can create a resource key using the 51Degrees Configurator.

Required NuGet Dependencies:

  1. Add Pipeline configuration options to appsettings.json. (or a separate file if you prefer. Just don't forget to add that file to your startup.cs) Example on-premise configuration:
    {
    "PipelineOptions": {
    "Elements": [
    {
    "BuilderName": "DeviceDetectionHashEngineBuilder",
    "BuildParameters": {
    "DataFile": "51Degrees-LiteV4.1.hash",
    "CreateTempDataCopy": false,
    "AutoUpdate": false,
    "PerformanceProfile": "LowMemory",
    "DataFileSystemWatcher": false,
    "DataUpdateOnStartUp": false
    }
    }
    ]
    }
    }

Example cloud configuration:

{
"PipelineOptions": {
"Elements": [
{
"BuilderName": "CloudRequestEngineBuilder",
"BuildParameters": {
"ResourceKey": "YourKey"
}
},
{
"BuilderName": "DeviceDetectionCloudEngineBuilder"
}
]
}
}
  1. Add builders and the Pipeline to the server's services.
    public class Startup
    {
    ...
    public void ConfigureServices(IServiceCollection services)
    {
    ...
    services.AddSingleton<DeviceDetectionHashEngineBuilder>();
    services.AddFiftyOne(Configuration);
    ...
  2. Configure the server to use the Pipeline which has just been set up.
    public class Startup
    {
    ...
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
    app.UseFiftyOne();
    ...
  3. Inject the IFlowDataProvider into a controller.
    public class HomeController : Controller
    {
    private IFlowDataProvider _flow;
    public HomeController(IFlowDataProvider flow)
    {
    _flow = flow;
    }
    ...
    }
  4. Pass the results contained in the flow data to the view.
    public class HomeController : Controller
    {
    ...
    public IActionResult Index()
    {
    var data = _flow.GetFlowData().Get<IDeviceData>();
    return View(data);
    }
    ...
  5. Display device details in the view.
    @model FiftyOne.DeviceDetection.IDeviceData
    ...
    var hardwareVendor = Model.HardwareVendor;
    ...
    Hardware Vendor: @(hardwareVendor.HasValue ? hardwareVendor.Value : $"Unknown ({hardwareVendor.NoValueMessage})")<br />
    ...

Controller

/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2019 51 Degrees Mobile Experts Limited, 5 Charlotte Close,
* Caversham, Reading, Berkshire, United Kingdom RG4 7BY.
*
* This Original Work is licensed under the European Union Public Licence (EUPL)
* v.1.2 and is subject to its terms as set out below.
*
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
*
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
*
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */
using System;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using FiftyOne.Pipeline.Web.Services;
using FiftyOne.Pipeline.Core.FlowElements;
{
public class HomeController : Controller
{
private IPipeline _pipeline;
private IWebRequestEvidenceService _evidenceService;
public HomeController(IPipeline pipeline,
IWebRequestEvidenceService evidenceService)
{
_pipeline = pipeline;
_evidenceService = evidenceService;
}
public IActionResult Index()
{
using(var flowData = _pipeline.CreateFlowData())
{
// Add evidence
_evidenceService.AddEvidenceFromRequest(flowData, Request);
// Process
flowData.Process();
// Set response headers
SetHeaderService.SetHeaders(Response.HttpContext, flowData);
// Send results to view
return View(flowData);
}
}
}
}

View

@model FiftyOne.Pipeline.Core.Data.IFlowData
@{
ViewData["Title"] = "User Agent Client Hints Example";
var deviceData = Model.Get<FiftyOne.DeviceDetection.IDeviceData>();
var hardwareVendor = deviceData.HardwareVendor;
var hardwareName = deviceData.HardwareName;
var deviceType = deviceData.DeviceType;
var platformVendor = deviceData.PlatformVendor;
var platformName = deviceData.PlatformName;
var platformVersion = deviceData.PlatformVersion;
var browserVendor = deviceData.BrowserVendor;
var browserName = deviceData.BrowserName;
var browserVersion = deviceData.BrowserVersion;
var engine = Model.Pipeline.GetElement<FiftyOne.DeviceDetection.Hash.Engine.OnPremise.FlowElements.DeviceDetectionHashEngine>();
}
<h2>User Agent Client Hints Example</h2>
<p>
By default, the user-agent, sec-ch-ua and sec-ch-ua-mobile HTTP headers
are sent.
<br />
This means that on the first request, the server can determine the
browser from sec-ch-ua while other details must be derived from the
user-agent.
<br />
If the server determines that the browser supports client hints, then
it may request additional client hints headers by setting the
Accept-CH header in the response.
<br />
Select the <strong>Make second request</strong> button below,
to use send another request to the server. This time, any
additional client hints headers that have been requested
will be included.
</p>
<button type="button" onclick="redirect()">Make second request</button>
<script>
// This script will run when button will be clicked and device detection request will again
// be sent to the server with all additional client hints that was requested in the previous
// response by the server.
// Following sequence will be followed.
// 1. User will send the first request to the web server for detection.
// 2. Web Server will return the properties in response based on the headers sent in the request. Along
// with the properties, it will also send a new header field Accept-CH in response indicating the additional
// evidence it needs. It builds the new response header using SetHeader[Component name]Accept-CH properties
// where Component Name is the name of the component for which properties are required.
// 3. When "Use User Agent Client Hints" button will be clicked, device detection request will again
// be sent to the server with all additional client hints that was requested in the previous
// response by the server.
// 4. Web Server will return the properties based on the new User Agent Client Hint headers
// being used as evidence.
function redirect() {
sessionStorage.reloadAfterPageLoad = true;
window.location.reload(true);
}
window.onload = function () {
if (sessionStorage.reloadAfterPageLoad) {
document.getElementById('description').innerHTML = "<p>The information shown below is determined using <strong>User Agent Client Hints</strong> that was sent in the request to obtain additional evidence. If no additional evidence appears in the table above, then it may indicate an external problem such as <strong>User Agent Client Hints</strong> being disabled or unsupported by your browser.</p>";
sessionStorage.reloadAfterPageLoad = false;
}
else {
document.getElementById('description').innerHTML = "<p>The following values are determined by sever-side device detection on the first request.</p>";
}
}
</script>
<div id="evidence">
<strong>Evidence values used:</strong>
<table>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
@foreach (var entry in Model.GetEvidence().AsDictionary()
.Where(e => engine.EvidenceKeyFilter.Include(e.Key)))
{
<tr>
<td>@(entry.Key)</td>
<td>@(entry.Value)</td>
</tr>
}
</table>
</div>
<br />
<div id=description></div>
<div id="content">
<strong>Detection results:</strong>
<p>
Hardware Vendor: @(hardwareVendor.HasValue ? hardwareVendor.Value : $"Unknown ({hardwareVendor.NoValueMessage})")<br />
Hardware Name: @(hardwareName.HasValue ? string.Join(", ", hardwareName.Value) : $"Unknown ({hardwareName.NoValueMessage})")<br />
Device Type: @(deviceType.HasValue ? deviceType.Value : $"Unknown ({deviceType.NoValueMessage})")<br />
Platform Vendor: @(platformVendor.HasValue ? platformVendor.Value : $"Unknown ({platformVendor.NoValueMessage})")<br />
Platform Name: @(platformName.HasValue ? platformName.Value : $"Unknown ({platformName.NoValueMessage})")<br />
Platform Version: @(platformVersion.HasValue ? platformVersion.Value : $"Unknown ({platformVersion.NoValueMessage})")<br />
Browser Vendor: @(browserVendor.HasValue ? browserVendor.Value : $"Unknown ({browserVendor.NoValueMessage})")<br />
Browser Name: @(browserName.HasValue ? browserName.Value : $"Unknown ({browserName.NoValueMessage})")<br />
Browser Version: @(browserVersion.HasValue ? browserVersion.Value : $"Unknown ({browserVersion.NoValueMessage})")
</p>
</div>

Startup

/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2019 51 Degrees Mobile Experts Limited, 5 Charlotte Close,
* Caversham, Reading, Berkshire, United Kingdom RG4 7BY.
*
* This Original Work is licensed under the European Union Public Licence (EUPL)
* v.1.2 and is subject to its terms as set out below.
*
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
*
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
*
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using FiftyOne.Common.Wrappers.IO;
using FiftyOne.Pipeline.Core.FlowElements;
using FiftyOne.Pipeline.Engines.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddTransient<HttpClient>();
services.AddSingleton<IFileWrapper, FileWrapper>();
services.AddSingleton<IFileSystem, RealFileSystem>();
services.AddSingleton<Func<TimerCallback, object, TimeSpan, Timer>>(
(callback, state, dueTime) =>
{
return new Timer(callback, state, (long)dueTime.TotalMilliseconds, Timeout.Infinite);
});
// Add the DataUpdate Service
services.AddSingleton<IDataUpdateService, DataUpdateService>();
services.AddSingleton<DeviceDetectionHashEngineBuilder>();
services.AddFiftyOne(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseFiftyOne();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}