Complete .NET Example
This example lists a device, creates an allocation, starts and stops one session, then releases the allocation. It is a complete console application and always attempts cleanup.
Prerequisites
dotnet new console -o device-park-quickstart
cd device-park-quickstart
dotnet add package Testinium.DevicePark
export DEVICEPARK_CLIENT_ID=your-client-id
export DEVICEPARK_CLIENT_SECRET=your-client-secretReplace the generated Program.cs with the following:
using Testinium.DevicePark;
using Testinium.DevicePark.Errors;
using Testinium.DevicePark.Models;
using var client = DeviceParkApiClient.Builder()
.Url("https://devicepark.testinium.io")
.Credentials(Credentials.FromEnvironment())
.Timeout(60)
.Build();
string? allocationId = null;
string? sessionId = null;
try
{
var devices = await client.Devices.ListAsync(new ListDevicesRequest.Builder()
.Page(0)
.Size(20)
.AddFilter(DeviceFilter.STATE, "HEALTHY", SearchOperation.EQUAL)
.Build());
var serial = devices.Data.FirstOrDefault(candidate => candidate.Serial is not null)?.Serial;
if (serial is null)
{
throw new InvalidOperationException("No visible device has a serial number");
}
var allocation = await client.Allocations.CreateAsync(new DeviceAllocationRequest.Builder()
.Serial(serial)
.Priority(3)
.Build());
allocationId = allocation.AllocationId
?? throw new InvalidOperationException("Allocation response does not contain allocationId");
if (allocation.DeviceSerial is null)
{
throw new InvalidOperationException(
$"Allocation {allocationId} is queued at position {allocation.Position?.ToString() ?? "unknown"}");
}
var session = await client.Sessions.StartAsync(new DeviceStartSessionRequest.Builder()
.AllocationId(allocationId)
.UserId(42)
.UserEmail("[email protected]")
.CompanyId(7)
.CompanyName("Example Company")
.VideoRecording(true)
.Build());
sessionId = session.SessionId
?? throw new InvalidOperationException("Session response does not contain sessionId");
Console.WriteLine($"allocationId={allocationId} sessionId={sessionId} deviceSerial={session.DeviceSerial}");
// Run Appium automation here while the session is active.
}
catch (DeviceParkHttpException error)
{
Console.Error.WriteLine($"Device Park request failed: {error.Status} {error.ErrorCode} {error.ErrorMessage}");
throw;
}
finally
{
if (sessionId is not null)
{
try
{
await client.Sessions.StopAsync(sessionId);
}
catch (DeviceParkException error)
{
Console.Error.WriteLine($"Could not stop session {sessionId}: {error.Message}");
}
}
if (allocationId is not null)
{
try
{
await client.Allocations.DeleteAsync(allocationId);
}
catch (DeviceParkException error)
{
Console.Error.WriteLine($"Could not release allocation {allocationId}: {error.Message}");
}
}
}Run it:
dotnet runThe client implements IDisposable, so the using declaration releases it when Main returns. There is no explicit close call.
The outer catch logs the error detail and rethrows, so the process exits with a non-zero code and CI treats the run as failed. The inner catch blocks inside finally deliberately swallow cleanup errors so that a failure while stopping the session does not replace the original test failure.
If the allocation enters the queue, this minimal example reports its position and releases it during cleanup. A production runner should keep the same allocationId, inspect List Allocations until DeviceSerial is assigned, and enforce its own maximum wait time.
A device must belong to a pool before it can be allocated. A device that appears in List Devices and reports a healthy state is not necessarily allocatable; if it belongs to no pool, allocation fails with ALLOCATION_ERR003. Add the device to a pool first, or ask a Device Park administrator to do so.
Target Frameworks
The SDK ships netstandard2.0, net472 and net8.0 assets and has no package dependencies, so this example also compiles unchanged in an older project. Replace the top-level statements with a Main method when targeting .NET Framework.
Project target | Asset used |
|---|---|
.NET Framework 4.7.2+ | net472 |
.NET Core 3.1, .NET 5, 6, 7 | netstandard2.0 |
.NET 8, 9, 10 and later | net8.0 |