\r\n

51Degrees Device Detection .NET  4.3

Device detection services for 51Degrees Pipeline

AspNetCore3.1-UACH/Startup.cs

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.Threading.Tasks;
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.AddControllersWithViews();
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();
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, IWebHostEnvironment env)
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
app.UseFiftyOne();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}