Configuring Port as part of Service Registration
I need to configure a dynamic port as part of my service registration during a generic host startup sequence. According to the dotnet docs, if you say your binding port is "0", then it'll allocate a dynamic port for you. My problem is how do I do this within the registration apis?
Hi, as far as I understand your use case you should:
- Bind the service to port "0"
- Start the service
- Read which actual port it was assigned to
- Provide an actual port to the registration API
Is it what you were after?
I have the same problem. How to get dynamic port in Startup.ConfigureServices method?
Yeah, I had to do exactly what you mention @marcin-krystianc. In order to achieve it, I had to build an alternative method to AgentServiceRegistration that looks like this:
namespace Consul.AspNetCore {
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class AgentServiceRegistrationWithDynamicPortHostedService : IHostedService {
private readonly IServer _server;
private readonly IConsulClient _consulClient;
private readonly AgentServiceRegistration _serviceRegistration;
private readonly ILogger _log;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
public AgentServiceRegistrationWithDynamicPortHostedService(ILoggerFactory loggerFactory,
IHostApplicationLifetime hostApplicationLifetime,
IServer server,
IConsulClient consulClient,
AgentServiceRegistration serviceRegistration) {
_log = loggerFactory.CreateLogger<AgentServiceRegistrationWithDynamicPortHostedService>();
_hostApplicationLifetime = hostApplicationLifetime;
_log.LogCritical("Logger instantiated.");
_server = server;
_consulClient = consulClient;
_serviceRegistration = serviceRegistration;
}
public Task StartAsync(CancellationToken cancellationToken) {
_hostApplicationLifetime.ApplicationStarted.Register(() => {
_log.LogInformation("Registering with Consul.");
var serverAddressesFeature = _server.Features.Get<IServerAddressesFeature>();
_log.LogInformation("Number of Uris: {@NumberOfUris}", serverAddressesFeature.Addresses.Count);
var possiblePorts = serverAddressesFeature.Addresses.Select(a => new Uri(a).Port).Distinct();
_serviceRegistration.Port = possiblePorts.FirstOrDefault();
_log.LogInformation("Reporting as bound to port: {@port}", _serviceRegistration.Port);
_log.LogInformation("Updating endpoints, replacing {port} with actual port number.");
if (_serviceRegistration.Check != null) {
_serviceRegistration.Check.HTTP = (_serviceRegistration.Check.HTTP ?? "").Replace("{port}", _serviceRegistration.Port.ToString());
_serviceRegistration.Check.TCP = (_serviceRegistration.Check.TCP ?? "").Replace("{port}", _serviceRegistration.Port.ToString());
}
foreach (var x in _serviceRegistration.Checks ?? new AgentServiceCheck[0]) {
x.HTTP = (x.HTTP ?? "").Replace("{port}", _serviceRegistration.Port.ToString());
x.TCP = (x.TCP ?? "").Replace("{port}", _serviceRegistration.Port.ToString());
}
_consulClient.Agent.ServiceRegister(_serviceRegistration, CancellationToken.None).GetAwaiter().GetResult();
});
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) {
return _consulClient.Agent.ServiceDeregister(_serviceRegistration.ID, cancellationToken);
}
}
public static class AdditionalServiceCollectionExtensions {
public static IServiceCollection AddConsulServiceRegistrationWithDynamicPort(this IServiceCollection services, Action<AgentServiceRegistration> configure) {
var registration = new AgentServiceRegistration();
configure.Invoke(registration);
return services
.AddSingleton(registration)
.AddHostedService<AgentServiceRegistrationWithDynamicPortHostedService>();
}
}
}
The key point with this... the app needs to be fully online before you can read the resolved IP Port and register. I didn't see an alternative way to gain the resolved IP. If someone has more information on how to better implement this, I'm game to listen and learn.