Skip to content

Commit e0cd1d2

Browse files
committed
Improve health check examples with error handling
Added robust error handling and admin privilege checks to all health check example programs. Updated endpoint binding logic to provide clearer instructions and feedback for common issues such as access denied and port conflicts. Added a README with usage instructions, troubleshooting tips, and endpoint details.
1 parent 175e37d commit e0cd1d2

5 files changed

Lines changed: 311 additions & 30 deletions

File tree

examples/Zetian.HealthCheck.Examples/BasicHealthCheckExample.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.Extensions.Logging;
2+
using System.Net;
23
using Zetian.Configuration;
34
using Zetian.HealthCheck.Extensions;
45

@@ -114,8 +115,28 @@ public static async Task RunAsync()
114115
}
115116
});
116117

117-
await healthCheckService.StartAsync();
118-
Console.WriteLine("Health check service started\n");
118+
try
119+
{
120+
await healthCheckService.StartAsync();
121+
Console.WriteLine("✓ Health check service started successfully\n");
122+
}
123+
catch (HttpListenerException ex) when (ex.ErrorCode == 5)
124+
{
125+
Console.WriteLine("\n❌ Access Denied: Cannot start health check service!");
126+
Console.WriteLine("\nSolution: Run this application as Administrator");
127+
Console.WriteLine("\nPress any key to exit...");
128+
Console.ReadKey();
129+
await smtpServer.StopAsync();
130+
return;
131+
}
132+
catch (Exception ex)
133+
{
134+
Console.WriteLine($"\n❌ Failed to start health check: {ex.Message}");
135+
Console.WriteLine("\nPress any key to exit...");
136+
Console.ReadKey();
137+
await smtpServer.StopAsync();
138+
return;
139+
}
119140

120141
// Print health check endpoints
121142
Console.WriteLine("Available health check endpoints:");

examples/Zetian.HealthCheck.Examples/CustomHealthCheckExample.cs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics;
2+
using System.Net;
23
using Zetian.Configuration;
34
using Zetian.HealthCheck.Extensions;
45

@@ -36,8 +37,7 @@ public static async Task RunAsync()
3637
{
3738
Prefixes = new()
3839
{
39-
"http://localhost:8080/health/",
40-
"http://+:8080/health/" // Listen on all interfaces
40+
"http://localhost:8080/health/"
4141
},
4242
DegradedStatusCode = 218 // "This is fine" status code
4343
};
@@ -51,6 +51,34 @@ public static async Task RunAsync()
5151

5252
HealthCheckService healthCheckService = smtpServer.EnableHealthCheck(serviceOptions, healthCheckOptions);
5353

54+
try
55+
{
56+
await healthCheckService.StartAsync();
57+
Console.WriteLine("Health check service started with custom configuration");
58+
Console.WriteLine("Health check available on localhost at port 8080");
59+
Console.WriteLine();
60+
}
61+
catch (HttpListenerException ex) when (ex.ErrorCode == 5)
62+
{
63+
Console.WriteLine("\n❌ Access Denied: Administrator privileges required!");
64+
Console.WriteLine("\nTo fix this, run one of the following:");
65+
Console.WriteLine("1. Run this application as Administrator");
66+
Console.WriteLine("2. Or add URL reservation (run as admin):");
67+
Console.WriteLine(" netsh http add urlacl url=http://+:8080/health/ user=Everyone");
68+
Console.WriteLine("\nPress any key to exit...");
69+
Console.ReadKey();
70+
await smtpServer.StopAsync();
71+
return;
72+
}
73+
catch (Exception ex)
74+
{
75+
Console.WriteLine($"\n❌ Failed to start health check: {ex.Message}");
76+
Console.WriteLine("\nPress any key to exit...");
77+
Console.ReadKey();
78+
await smtpServer.StopAsync();
79+
return;
80+
}
81+
5482
// Add custom health checks
5583
healthCheckService.AddHealthCheck("system_resources", async (ct) =>
5684
{
@@ -115,11 +143,7 @@ public static async Task RunAsync()
115143
}
116144
});
117145

118-
await healthCheckService.StartAsync();
119-
120-
Console.WriteLine("Health check service started with custom configuration");
121-
Console.WriteLine("Health check available on all interfaces at port 8080");
122-
Console.WriteLine();
146+
// Health check already started above
123147
Console.WriteLine("Available endpoints:");
124148
Console.WriteLine(" - http://localhost:8080/health/");
125149
Console.WriteLine(" - http://localhost:8080/health/livez");

examples/Zetian.HealthCheck.Examples/HealthCheckWithBindingExample.cs

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,44 +29,113 @@ public static async Task RunAsync()
2929
IPAddress specificIP = IPAddress.Parse("127.0.0.1");
3030
Console.WriteLine($"Starting health check on IP: {specificIP}");
3131
HealthCheckService healthCheckOnIP = smtpServer.EnableHealthCheck(specificIP, 8081);
32-
await healthCheckOnIP.StartAsync();
33-
Console.WriteLine("Health check available at: http://127.0.0.1:8081/health/\n");
32+
33+
try
34+
{
35+
await healthCheckOnIP.StartAsync();
36+
Console.WriteLine("Health check available at: http://127.0.0.1:8081/health/\n");
37+
}
38+
catch (Exception ex)
39+
{
40+
Console.WriteLine($"❌ Failed to start health check on {specificIP}: {ex.Message}\n");
41+
}
3442

3543
// Example 2: Bind health check to all interfaces
36-
Console.WriteLine("Starting health check on all interfaces");
37-
HealthCheckService healthCheckOnAll = smtpServer.EnableHealthCheck("0.0.0.0", 8082);
38-
await healthCheckOnAll.StartAsync();
39-
Console.WriteLine("Health check available at: http://0.0.0.0:8082/health/");
40-
Console.WriteLine(" and: http://localhost:8082/health/");
41-
Console.WriteLine(" and: http://[your-ip]:8082/health/\n");
44+
Console.WriteLine("Starting health check on all interfaces (0.0.0.0)");
45+
HealthCheckService? healthCheckOnAll = null;
46+
47+
try
48+
{
49+
healthCheckOnAll = smtpServer.EnableHealthCheck("0.0.0.0", 8082);
50+
await healthCheckOnAll.StartAsync();
51+
Console.WriteLine("✓ Health check available at:");
52+
Console.WriteLine(" - http://localhost:8082/health/");
53+
Console.WriteLine(" - http://[your-ip]:8082/health/\n");
54+
}
55+
catch (HttpListenerException ex) when (ex.ErrorCode == 5)
56+
{
57+
Console.WriteLine("❌ Access Denied: Administrator privileges required!");
58+
Console.WriteLine("To listen on all interfaces, you need to:");
59+
Console.WriteLine("1. Run as Administrator, or");
60+
Console.WriteLine("2. Add URL reservation (run cmd as admin):");
61+
Console.WriteLine(" netsh http add urlacl url=http://+:8082/health/ user=Everyone\n");
62+
}
63+
catch (HttpListenerException ex) when (ex.ErrorCode == 183)
64+
{
65+
Console.WriteLine("❌ Cannot create a file when that file already exists.");
66+
Console.WriteLine("Another application may be using port 8082.\n");
67+
}
68+
catch (Exception ex)
69+
{
70+
Console.WriteLine($"❌ Failed: {ex.Message}\n");
71+
}
4272

4373
// Example 3: Bind to specific hostname
44-
Console.WriteLine("Starting health check with hostname");
45-
HealthCheckService healthCheckWithHost = smtpServer.EnableHealthCheck("localhost", 8083);
46-
await healthCheckWithHost.StartAsync();
47-
Console.WriteLine("Health check available at: http://localhost:8083/health/\n");
74+
Console.WriteLine("Starting health check with hostname (localhost)");
75+
HealthCheckService? healthCheckWithHost = null;
76+
77+
try
78+
{
79+
healthCheckWithHost = smtpServer.EnableHealthCheck("localhost", 8083);
80+
await healthCheckWithHost.StartAsync();
81+
Console.WriteLine("✓ Health check available at: http://localhost:8083/health/\n");
82+
}
83+
catch (Exception ex)
84+
{
85+
Console.WriteLine($"❌ Failed to start health check on localhost: {ex.Message}\n");
86+
}
4887

4988
// Example 4: IPv6 binding (if supported)
89+
HealthCheckService? healthCheckIPv6 = null;
90+
5091
try
5192
{
5293
IPAddress ipv6Address = IPAddress.IPv6Loopback;
5394
Console.WriteLine($"Starting health check on IPv6: {ipv6Address}");
54-
HealthCheckService healthCheckIPv6 = smtpServer.EnableHealthCheck(ipv6Address, 8084);
95+
healthCheckIPv6 = smtpServer.EnableHealthCheck(ipv6Address, 8084);
5596
await healthCheckIPv6.StartAsync();
56-
Console.WriteLine("Health check available at: http://[::1]:8084/health/\n");
97+
Console.WriteLine("✓ Health check available at: http://[::1]:8084/health/\n");
98+
}
99+
catch (HttpListenerException ex)
100+
{
101+
Console.WriteLine($"❌ IPv6 binding failed: {ex.Message}");
102+
Console.WriteLine("IPv6 may not be supported or enabled on this system.\n");
57103
}
58104
catch (Exception ex)
59105
{
60-
Console.WriteLine($"IPv6 not supported: {ex.Message}\n");
106+
Console.WriteLine($"IPv6 not supported: {ex.Message}\n");
61107
}
62108

109+
// Show summary
110+
Console.WriteLine("=====================================");
111+
Console.WriteLine("Summary:");
112+
Console.WriteLine("ℹ Localhost bindings usually work without admin rights");
113+
Console.WriteLine("ℹ Binding to 0.0.0.0 or specific IPs requires admin rights");
114+
Console.WriteLine("ℹ Use URL ACL reservations for non-admin access");
115+
Console.WriteLine("=====================================");
116+
63117
Console.WriteLine("\nPress any key to stop...");
64118
Console.ReadKey();
65119

66120
// Stop all health check services
67-
await healthCheckOnIP.StopAsync();
68-
await healthCheckOnAll.StopAsync();
69-
await healthCheckWithHost.StopAsync();
121+
Console.WriteLine("\nStopping services...");
122+
123+
try { await healthCheckOnIP.StopAsync(); } catch { }
124+
if (healthCheckOnAll != null)
125+
{
126+
try { await healthCheckOnAll.StopAsync(); } catch { }
127+
}
128+
129+
if (healthCheckWithHost != null)
130+
{
131+
try { await healthCheckWithHost.StopAsync(); } catch { }
132+
}
133+
134+
if (healthCheckIPv6 != null)
135+
{
136+
try { await healthCheckIPv6.StopAsync(); } catch { }
137+
}
138+
70139
await smtpServer.StopAsync();
71140

72141
Console.WriteLine("Example completed.");

examples/Zetian.HealthCheck.Examples/Program.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Security.Principal;
12
using System.Text;
23

34
namespace Zetian.HealthCheck.Examples
@@ -12,9 +13,27 @@ static async Task Main(string[] args)
1213
Console.WriteLine("Zetian Health Check Examples");
1314
Console.WriteLine("=============================");
1415
Console.WriteLine();
15-
Console.WriteLine("1. Basic Health Check");
16-
Console.WriteLine("2. Health Check with Custom Options");
17-
Console.WriteLine("3. Health Check with IP/Hostname Binding");
16+
17+
// Check if running as admin
18+
bool isAdmin = false;
19+
if (OperatingSystem.IsWindows())
20+
{
21+
using WindowsIdentity identity = WindowsIdentity.GetCurrent();
22+
WindowsPrincipal principal = new(identity);
23+
isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
24+
}
25+
26+
if (!isAdmin && OperatingSystem.IsWindows())
27+
{
28+
Console.ForegroundColor = ConsoleColor.Yellow;
29+
Console.WriteLine("⚠ Note: Some examples may require administrator privileges on Windows.");
30+
Console.WriteLine(" Run this application as Administrator for full functionality.\n");
31+
Console.ResetColor();
32+
}
33+
34+
Console.WriteLine("1. Basic Health Check (localhost - usually works without admin)");
35+
Console.WriteLine("2. Health Check with Custom Options (localhost - usually works without admin)");
36+
Console.WriteLine("3. Health Check with IP/Hostname Binding (may require admin)");
1837
Console.WriteLine();
1938
Console.Write("Select an example (1-3): ");
2039

0 commit comments

Comments
 (0)