Detection of the specific models of Apple devices being used to make a request is more difficult than it is for other vendors.Typically, the 51Degrees approach is to use dynamically generated JavaScript to determine the model on the client-side and pass this back to the server. Some users are unable or unwilling to deploy dynamic JavaScript. In this case 51Degrees have an alternative approach in which the required data is gathered using static JavaScript. This is then passed to the server to determine the Apple model.
This example demonstrates this alternative approach.
This example requires a paid-for data file as the device model properties are not available in the free, 'lite' data file. See our pricing page for details on how to obtain one.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
// For a sample configuration file demonstrating all available options, see
// https://github.com/51Degrees/device-detection-dotnet-examples/blob/main/Examples/sample-configuration.json
"PipelineOptions": {
"Elements": [
{
"BuilderName": "AppleProfileEngineBuilder",
"BuildParameters": {
"DataFile": "macintosh.data.json",
"CreateTempDataCopy": false,
"AutoUpdate": true,
"DataFileSystemWatcher": false,
"DataUpdateOnStartUp": true,
"DataUpdateUrl": "https://cloud.51degrees.com/cdn/macintosh.data.json",
"UpdatePollingInterval": "86400"
}
},
{
"BuilderName": "DeviceDetectionHashEngineBuilder",
"BuildParameters": {
"DataFile": "Enterprise-HashV41.hash",
"CreateTempDataCopy": false,
"AutoUpdate": false,
"PerformanceProfile": "LowMemory",
"DataFileSystemWatcher": false,
"DataUpdateOnStartUp": false
}
}
]
}
}
using FiftyOne.Pipeline.Core.Configuration;
using FiftyOne.Pipeline.Core.FlowElements;
using FiftyOne.Pipeline.Engines.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
{
class Program
{
public class Example : AppleExampleBase
{
private IPipeline _pipeline;
{
_pipeline = pipeline;
}
public void Run(TextWriter output)
{
var data = new List<Dictionary<string, object>>()
{
new Dictionary<string, object>()
{
{
FiftyOne.Pipeline.Core.Constants.EVIDENCE_HEADER_USERAGENT_KEY,
"Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1" },
}
};
foreach (var values in data)
{
AnalyseEvidence(values, output);
}
}
private void AnalyseEvidence(
Dictionary<string, object> evidence,
TextWriter output)
{
using (var data = _pipeline.CreateFlowData())
{
StringBuilder message = new StringBuilder();
message.AppendLine("Input values:");
foreach (var entry in evidence)
{
message.AppendLine($"\t{entry.Key}: {entry.Value}");
}
output.WriteLine(message.ToString());
data.AddEvidence(evidence);
data.Process();
message = new StringBuilder();
message.AppendLine("Results:");
var device = data.Get<IDeviceData>();
OutputValue("Model Name(s)", device.HardwareName, message);
output.WriteLine(message.ToString());
}
}
private void OutputValue(string name,
IAspectPropertyValue<IReadOnlyList<string>> value,
StringBuilder message)
{
message.AppendLine(value.HasValue ?
$"\t{name}: " + string.Join(", ", value.Value) :
$"\t{name}: " + value.NoValueMessage);
}
public static void Run(PipelineOptions options, TextWriter output)
{
using (var serviceProvider = new ServiceCollection()
.AddLogging(l => l.AddConsole())
.AddSingleton<HttpClient>()
.AddSingleton<IDataUpdateService, DataUpdateService>()
.AddSingleton(options)
.AddTransient<AppleProfileEngineBuilder>()
.AddTransient<DeviceDetectionHashEngineBuilder>()
.AddTransient<PipelineBuilder>()
.AddSingleton((x) =>
{
return x.GetRequiredService<PipelineBuilder>()
.BuildFromConfiguration(x.GetRequiredService<PipelineOptions>());
})
.AddTransient<Example>()
.BuildServiceProvider())
{
var engine = serviceProvider.GetRequiredService<IPipeline>()
.GetElement<DeviceDetectionHashEngine>();
if (CheckDataFiles(
serviceProvider.GetRequiredService<ILogger<Program>>(),
engine,
options.GetHashDataFile(),
options.GetAppleDataFile()))
{
serviceProvider.GetRequiredService<
Example>().Run(output);
}
}
}
}
static void Main(string[] args)
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
PipelineOptions options = new PipelineOptions();
var section = config.GetRequiredSection("PipelineOptions");
section.Bind(options, (o) => { o.ErrorOnUnknownConfiguration = true; });
var hashFileFromConfig = options.GetHashDataFile();
options.SetHashDataFile(GetCompleteFilename(hashFileFromConfig,
Constants.ENTERPRISE_HASH_DATA_FILE_NAME));
var appleFileFromConfig = options.GetAppleDataFile();
options.SetAppleDataFile(GetCompleteFilename(appleFileFromConfig,
Constants.APPLE_DATA_FILE_NAME));
Example.Run(options, Console.Out);
}
private static string GetCompleteFilename(string filenameFromConfig, string defaultName)
{
if (string.IsNullOrWhiteSpace(filenameFromConfig))
{
return ExampleUtils.FindFile(defaultName);
}
else if (Path.IsPathRooted(filenameFromConfig) == false)
{
return ExampleUtils.FindFile(filenameFromConfig);
}
return filenameFromConfig;
}
}
}