NetDiag .NET Client | Xakpc.NetDiag.Client NuGet Package
Official .NET SDK for NetDiag API. Run network diagnostics from C# applications with dependency injection, async/await, and .NET 8/9 support.
Official .NET SDK for NetDiag API
Installation
dotnet add package Xakpc.NetDiag.Client
Or add to your project file:
<PackageReference Include="Xakpc.NetDiag.Client" Version="*" />
Requirements: .NET 8.0 or .NET 9.0
Quick Start
using Xakpc.NetDiag.Client;
// Create client with API key
using var client = new NetDiagClient("your-api-key");
// Run diagnostics on a target
var result = await client.CheckAsync("example.com");
Console.WriteLine(result.Status); // Healthy, Warning, or Unhealthy
Console.WriteLine(result.Quorum); // "3/3"
Console.WriteLine(result.Locations); // Per-region results
For quick health checks:
// Simple boolean check
bool isUp = await client.IsHealthyAsync("example.com");
// Get status enum
Status status = await client.GetStatusAsync("example.com");
Dependency Injection
Register the client in your ASP.NET Core application:
// Program.cs or Startup.cs
builder.Services.AddNetDiagClient(options =>
{
options.ApiKey = builder.Configuration["NetDiag:ApiKey"];
});
Then inject INetDiagClient:
public class HealthController : ControllerBase
{
private readonly INetDiagClient _netDiag;
public HealthController(INetDiagClient netDiag)
{
_netDiag = netDiag;
}
[HttpGet("check/{target}")]
public async Task<IActionResult> Check(string target)
{
var result = await _netDiag.CheckAsync(target);
return Ok(result);
}
}
Configuration via appsettings.json
{
"NetDiag": {
"ApiKey": "your-api-key",
"BaseUrl": "https://api.netdiag.dev",
"Timeout": "00:00:30"
}
}
builder.Services.AddNetDiagClient(
builder.Configuration.GetSection("NetDiag")
);
API Reference
Constructors
// Default (no API key, rate-limited)
new NetDiagClient()
// With API key
new NetDiagClient(string apiKey)
// With full options
new NetDiagClient(NetDiagClientOptions options)
// For DI with custom HttpClient
new NetDiagClient(HttpClient httpClient, IOptions<NetDiagClientOptions> options)
Methods
CheckAsync
Run full diagnostics on a target.
Task<CheckResponse> CheckAsync(string target, CancellationToken ct = default)
Task<CheckResponse> CheckAsync(ChecksRequest request, CancellationToken ct = default)
Examples:
// Simple check with just hostname
var result = await client.CheckAsync("example.com");
// Check with options
var result = await client.CheckAsync(new ChecksRequest
{
Target = "example.com",
Port = 443,
PingCount = 10,
Regions = "us-east,eu-west,ap-southeast"
});
CheckPrometheusAsync
Get diagnostics results in Prometheus metrics format.
Task<string> CheckPrometheusAsync(string target, CancellationToken ct = default)
Task<string> CheckPrometheusAsync(ChecksRequest request, CancellationToken ct = default)
Example:
string metrics = await client.CheckPrometheusAsync("example.com");
// Returns Prometheus-formatted metrics string
IsHealthyAsync
Quick boolean health check.
Task<bool> IsHealthyAsync(string target, CancellationToken ct = default)
Example:
if (await client.IsHealthyAsync("api.example.com"))
{
Console.WriteLine("Service is healthy!");
}
GetStatusAsync
Get the status enum for a target.
Task<Status> GetStatusAsync(string target, CancellationToken ct = default)
Example:
var status = await client.GetStatusAsync("example.com");
switch (status)
{
case Status.Healthy:
Console.WriteLine("All systems operational");
break;
case Status.Warning:
Console.WriteLine("Degraded performance");
break;
case Status.Unhealthy:
Console.WriteLine("Service is down");
break;
}
Request Options
When using ChecksRequest:
| Property | Type | Default | Description |
|---|---|---|---|
Target |
string |
required | Hostname, IP address, or URL to check |
Port |
int? |
443 |
Port to check (80, 443, 8080, 8443) |
PingCount |
int? |
4 |
Number of ping packets (1-100) |
PingTimeout |
int? |
5 |
Ping timeout in seconds (1-30) |
Dns |
string? |
null |
Custom DNS server to use |
Regions |
string? |
null |
Comma-separated region codes |
Available Regions: us-east, us-west, eu-west, eu-central, ap-southeast, ap-northeast
Response Types
CheckResponse
public record CheckResponse
{
public string RunId { get; init; }
public string Target { get; init; }
public Status Status { get; init; }
public string Quorum { get; init; }
public string DnsPropagationStatus { get; init; }
public DateTimeOffset StartedAt { get; init; }
public DateTimeOffset CompletedAt { get; init; }
public IReadOnlyList<LocationResult> Locations { get; init; }
}
LocationResult
public record LocationResult
{
public string Region { get; init; }
public Status Status { get; init; }
public PingResult? Ping { get; init; }
public DnsResult? Dns { get; init; }
public TlsResult? Tls { get; init; }
public HttpResult? Http { get; init; }
}
Diagnostic Results
public record PingResult
{
public Status Status { get; init; }
public double LatencyMs { get; init; }
public double? MinRttMs { get; init; }
public double? MaxRttMs { get; init; }
public double? PacketLossPercent { get; init; }
public bool TcpFallbackUsed { get; init; }
public string? Message { get; init; }
public ErrorInfo? Error { get; init; }
}
public record DnsResult
{
public Status Status { get; init; }
public IReadOnlyList<string> ResolvedAddresses { get; init; }
public string? Message { get; init; }
public ErrorInfo? Error { get; init; }
}
public record TlsResult
{
public Status Status { get; init; }
public bool CertificateValid { get; init; }
public int? DaysUntilExpiry { get; init; }
public DateTimeOffset? ExpiresAt { get; init; }
public string? Subject { get; init; }
public string? Issuer { get; init; }
public string? Protocol { get; init; }
public string? Message { get; init; }
public ErrorInfo? Error { get; init; }
}
public record HttpResult
{
public Status Status { get; init; }
public int? StatusCode { get; init; }
public string? ReasonPhrase { get; init; }
public double? ResponseTimeMs { get; init; }
public string? Message { get; init; }
public ErrorInfo? Error { get; init; }
}
Error Handling
The client throws typed exceptions for different failure scenarios:
using Xakpc.NetDiag.Client;
using Xakpc.NetDiag.Client.Exceptions;
try
{
var result = await client.CheckAsync("example.com");
}
catch (NetDiagRateLimitException ex)
{
// Rate limited - wait and retry
Console.WriteLine($"Retry after {ex.RetryAfterSeconds} seconds");
await Task.Delay(TimeSpan.FromSeconds(ex.RetryAfterSeconds));
}
catch (NetDiagApiException ex)
{
// API error (4xx/5xx)
Console.Error.WriteLine($"API Error: {ex.StatusCode} - {ex.ReasonPhrase}");
}
catch (NetDiagException ex)
{
// Other client errors
Console.Error.WriteLine($"Client Error: {ex.Message}");
}
Exception Types
| Exception | Description |
|---|---|
NetDiagException |
Base exception for all client errors |
NetDiagApiException |
HTTP errors with StatusCode and ReasonPhrase |
NetDiagRateLimitException |
Rate limit exceeded with RetryAfterSeconds |
Polly Retry Example
using Polly;
var retryPolicy = Policy
.Handle<NetDiagRateLimitException>()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: (retryAttempt, exception, context) =>
{
if (exception is NetDiagRateLimitException rle)
return TimeSpan.FromSeconds(rle.RetryAfterSeconds);
return TimeSpan.FromSeconds(Math.Pow(2, retryAttempt));
},
onRetryAsync: (exception, timespan, retryAttempt, context) =>
{
Console.WriteLine($"Retry {retryAttempt} after {timespan}");
return Task.CompletedTask;
}
);
var result = await retryPolicy.ExecuteAsync(
() => client.CheckAsync("example.com")
);
Advanced Usage
Custom HttpClient
Provide your own HttpClient for advanced scenarios:
var httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(60)
};
var options = Options.Create(new NetDiagClientOptions
{
ApiKey = "your-api-key"
});
var client = new NetDiagClient(httpClient, options);
ASP.NET Core Health Checks Integration
public class NetDiagHealthCheck : IHealthCheck
{
private readonly INetDiagClient _client;
private readonly string _target;
public NetDiagHealthCheck(INetDiagClient client, string target)
{
_client = client;
_target = target;
}
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken ct = default)
{
try
{
var status = await _client.GetStatusAsync(_target, ct);
return status switch
{
Status.Healthy => HealthCheckResult.Healthy(),
Status.Warning => HealthCheckResult.Degraded(),
_ => HealthCheckResult.Unhealthy()
};
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy(ex.Message);
}
}
}
Prometheus Metrics Endpoint
app.MapGet("/metrics", async (INetDiagClient client) =>
{
var metrics = await client.CheckPrometheusAsync("your-service.com");
return Results.Text(metrics, "text/plain");
});
IDisposable Pattern
The client implements IDisposable. When creating the client directly (not via DI), dispose it when done:
using var client = new NetDiagClient("your-api-key");
var result = await client.CheckAsync("example.com");
// Client is automatically disposed
Note: The client only disposes the
HttpClientif it created one internally. When using DI or providing your ownHttpClient, you're responsible for its lifecycle.