diff --git a/HealthMonitoring.Client/HealthMonitoring.Client.csproj b/HealthMonitoring.Client/HealthMonitoring.Client.csproj
index bbed55a..b8ca7c0 100644
--- a/HealthMonitoring.Client/HealthMonitoring.Client.csproj
+++ b/HealthMonitoring.Client/HealthMonitoring.Client.csproj
@@ -9,6 +9,8 @@
+
+
diff --git a/HealthMonitoring.Client/HealthMonitoringRegistrationExtensions.cs b/HealthMonitoring.Client/HealthMonitoringRegistrationExtensions.cs
new file mode 100644
index 0000000..96d9e28
--- /dev/null
+++ b/HealthMonitoring.Client/HealthMonitoringRegistrationExtensions.cs
@@ -0,0 +1,58 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace HealthMonitoring.Client;
+
+public sealed class HealthMonitoringRegistrationConfiguration
+{
+ public Uri MonitoringServerUrl { get; set; } = new("http://localhost:9620/");
+ public ServiceRegistrationOptions Service { get; set; } = new();
+ public List Dependencies { get; set; } = [];
+}
+
+public sealed class HealthMonitoringRegistrationHostedService(
+ IHealthMonitoringRegistrationClient client,
+ HealthMonitoringRegistrationConfiguration configuration) : IHostedService
+{
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ await client.RegisterAndConfigureAsync(
+ configuration.Service,
+ configuration.Dependencies,
+ cancellationToken);
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+}
+
+public static class HealthMonitoringRegistrationExtensions
+{
+ public static IServiceCollection AddHealthMonitoringRegistration(
+ this IServiceCollection services,
+ IConfiguration configuration,
+ string sectionName = "HealthMonitoring")
+ {
+ ArgumentNullException.ThrowIfNull(services);
+ ArgumentNullException.ThrowIfNull(configuration);
+ ArgumentException.ThrowIfNullOrWhiteSpace(sectionName);
+
+ var section = configuration.GetSection(sectionName);
+ if (!section.Exists())
+ return services;
+
+ var registration = new HealthMonitoringRegistrationConfiguration();
+ section.Bind(registration);
+ if (!registration.MonitoringServerUrl.IsAbsoluteUri)
+ throw new ArgumentException("The monitoring server URL must be absolute.", nameof(configuration));
+
+ services.AddSingleton(registration);
+ services.AddHttpClient(client =>
+ {
+ client.BaseAddress = registration.MonitoringServerUrl;
+ });
+ services.AddHostedService();
+
+ return services;
+ }
+}
diff --git a/HealthMonitoring.Client/README.md b/HealthMonitoring.Client/README.md
index be4816f..0c98c47 100644
--- a/HealthMonitoring.Client/README.md
+++ b/HealthMonitoring.Client/README.md
@@ -2,6 +2,36 @@
Reusable .NET client for service self-registration and dependency mapping.
+For automatic registration at application startup, add this configuration:
+
+```json
+{
+ "HealthMonitoring": {
+ "MonitoringServerUrl": "http://localhost:9620/",
+ "Service": {
+ "ServiceId": "payments-api",
+ "Name": "Payments API",
+ "HealthUrl": "https://payments-api/health"
+ },
+ "Dependencies": [
+ {
+ "DependencyName": "Security Service",
+ "TargetServiceId": "security-service"
+ }
+ ]
+ }
+}
+```
+
+Then add one line during service registration:
+
+```csharp
+services.AddHealthMonitoringRegistration(configuration);
+```
+
+The client registers the service and dependency mappings once during application startup. Registration is idempotent.
+If the `HealthMonitoring` section is absent, no registration is attempted and the application starts normally.
+
```csharp
services.AddHealthMonitoringRegistrationClient(options =>
{
diff --git a/HealthMonitoring.Tests/Client/HealthMonitoringRegistrationExtensionsTests.cs b/HealthMonitoring.Tests/Client/HealthMonitoringRegistrationExtensionsTests.cs
new file mode 100644
index 0000000..9584cca
--- /dev/null
+++ b/HealthMonitoring.Tests/Client/HealthMonitoringRegistrationExtensionsTests.cs
@@ -0,0 +1,103 @@
+using HealthMonitoring.Client;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace HealthMonitoring.Tests.Client;
+
+public sealed class HealthMonitoringRegistrationExtensionsTests
+{
+ [Fact]
+ public void Configuration_registration_binds_service_settings_and_adds_startup_registration()
+ {
+ var configuration = new ConfigurationBuilder()
+ .AddInMemoryCollection(new Dictionary
+ {
+ ["HealthMonitoring:MonitoringServerUrl"] = "https://monitoring.example/",
+ ["HealthMonitoring:Service:ServiceId"] = "mobile-configuration",
+ ["HealthMonitoring:Service:Name"] = "Mobile Configuration",
+ ["HealthMonitoring:Service:HealthUrl"] = "https://mobile.example/healthui",
+ ["HealthMonitoring:Service:Description"] = "Mobile Configuration",
+ ["HealthMonitoring:Service:PollingInterval"] = "00:02:00",
+ ["HealthMonitoring:Dependencies:0:DependencyName"] = "Security Service",
+ ["HealthMonitoring:Dependencies:0:TargetServiceId"] = "security-service"
+ })
+ .Build();
+
+ var services = new ServiceCollection();
+
+ services.AddHealthMonitoringRegistration(configuration);
+
+ using var provider = services.BuildServiceProvider();
+ var options = provider.GetRequiredService();
+
+ Assert.Equal(new Uri("https://monitoring.example/"), options.MonitoringServerUrl);
+ Assert.Equal("mobile-configuration", options.Service.ServiceId);
+ Assert.Equal(TimeSpan.FromMinutes(2), options.Service.PollingInterval);
+ Assert.Single(options.Dependencies);
+ Assert.Contains(provider.GetServices(), service => service is HealthMonitoringRegistrationHostedService);
+ }
+
+ [Fact]
+ public void Missing_configuration_section_skips_automatic_registration()
+ {
+ var configuration = new ConfigurationBuilder().Build();
+ var services = new ServiceCollection();
+
+ services.AddHealthMonitoringRegistration(configuration);
+
+ using var provider = services.BuildServiceProvider();
+
+ Assert.Empty(provider.GetServices());
+ Assert.Throws(() =>
+ provider.GetRequiredService());
+ }
+
+ [Fact]
+ public async Task Startup_registration_calls_register_and_configure()
+ {
+ var configuration = new HealthMonitoringRegistrationConfiguration
+ {
+ Service = new ServiceRegistrationOptions
+ {
+ ServiceId = "mobile-configuration",
+ Name = "Mobile Configuration",
+ HealthUrl = new Uri("https://mobile.example/healthui")
+ },
+ Dependencies = [new DependencyMappingOptions("Security Service", "security-service")]
+ };
+ var client = new RecordingRegistrationClient();
+
+ await new HealthMonitoringRegistrationHostedService(client, configuration)
+ .StartAsync(CancellationToken.None);
+
+ Assert.Same(configuration.Service, client.Service);
+ Assert.Same(configuration.Dependencies, client.Dependencies);
+ }
+
+ private sealed class RecordingRegistrationClient : IHealthMonitoringRegistrationClient
+ {
+ public ServiceRegistrationOptions? Service { get; private set; }
+ public IEnumerable? Dependencies { get; private set; }
+
+ public Task RegisterAsync(ServiceRegistrationOptions options, CancellationToken cancellationToken = default)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ throw new NotSupportedException($"RegisterAsync is not used for {options.ServiceId}.");
+ }
+
+ public Task SetDependencyMappingsAsync(string serviceId, IEnumerable mappings, CancellationToken cancellationToken = default)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ throw new NotSupportedException($"SetDependencyMappingsAsync is not used for {serviceId} with {mappings.Count()} mappings.");
+ }
+
+ public Task RegisterAndConfigureAsync(ServiceRegistrationOptions options, IEnumerable mappings, CancellationToken cancellationToken = default)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ Service = options;
+ Dependencies = mappings;
+ return Task.FromResult(new ServiceRegistrationResult(options.ServiceId, "created", Guid.NewGuid()));
+ }
+ }
+}