diff --git a/src/Common/src/Common/Discovery/IServiceInstance.cs b/src/Common/src/Common/Discovery/IServiceInstance.cs
index 8f23b8ef3d..8a1c5cac8c 100644
--- a/src/Common/src/Common/Discovery/IServiceInstance.cs
+++ b/src/Common/src/Common/Discovery/IServiceInstance.cs
@@ -11,6 +11,11 @@ public interface IServiceInstance
///
string ServiceId { get; }
+ ///
+ /// Gets the instance ID as registered by the discovery client.
+ ///
+ string InstanceId { get; }
+
///
/// Gets the hostname of the registered service instance.
///
diff --git a/src/Common/src/Common/PublicAPI.Unshipped.txt b/src/Common/src/Common/PublicAPI.Unshipped.txt
index 7dc5c58110..0c34fd435f 100644
--- a/src/Common/src/Common/PublicAPI.Unshipped.txt
+++ b/src/Common/src/Common/PublicAPI.Unshipped.txt
@@ -1 +1,2 @@
#nullable enable
+Steeltoe.Common.Discovery.IServiceInstance.InstanceId.get -> string!
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs
index 6638ca8c82..7bbfb0f21b 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs
@@ -373,8 +373,8 @@ public void UpdateSettingsFromDiscovery_UpdatesSettingsCorrectly()
List instances =
[
- new TestServiceInstance("i1", new Uri("https://foo.bar:8888/"), metadata1),
- new TestServiceInstance("i2", new Uri("https://foo.bar.baz:9999/"), metadata2)
+ new TestServiceInstance("s", "i1", new Uri("https://foo.bar:8888/"), metadata1),
+ new TestServiceInstance("s", "i2", new Uri("https://foo.bar.baz:9999/"), metadata2)
];
provider.UpdateSettingsFromDiscovery(instances, options);
@@ -416,9 +416,10 @@ private static string GetEncodedUserPassword(string user, string password)
return Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{password}"));
}
- private sealed class TestServiceInstance(string serviceId, Uri uri, IReadOnlyDictionary metadata) : IServiceInstance
+ private sealed class TestServiceInstance(string serviceId, string instanceId, Uri uri, IReadOnlyDictionary metadata) : IServiceInstance
{
public string ServiceId { get; } = serviceId;
+ public string InstanceId { get; } = instanceId;
public string Host { get; } = uri.Host;
public int Port { get; } = uri.Port;
public bool IsSecure { get; } = uri.Scheme == Uri.UriSchemeHttps;
diff --git a/src/Discovery/src/Configuration/ConfigurationServiceInstance.cs b/src/Discovery/src/Configuration/ConfigurationServiceInstance.cs
index 4b96049165..f5ac148f17 100644
--- a/src/Discovery/src/Configuration/ConfigurationServiceInstance.cs
+++ b/src/Discovery/src/Configuration/ConfigurationServiceInstance.cs
@@ -22,6 +22,9 @@ public sealed class ConfigurationServiceInstance : IServiceInstance
[Required]
public string? ServiceId { get; set; }
+ ///
+ public string InstanceId => string.Empty;
+
///
[Required]
public string? Host { get; set; }
diff --git a/src/Discovery/src/Configuration/PublicAPI.Unshipped.txt b/src/Discovery/src/Configuration/PublicAPI.Unshipped.txt
index 7dc5c58110..8a7cac8051 100644
--- a/src/Discovery/src/Configuration/PublicAPI.Unshipped.txt
+++ b/src/Discovery/src/Configuration/PublicAPI.Unshipped.txt
@@ -1 +1,2 @@
#nullable enable
+Steeltoe.Discovery.Configuration.ConfigurationServiceInstance.InstanceId.get -> string!
diff --git a/src/Discovery/src/Consul/ConsulServiceInstance.cs b/src/Discovery/src/Consul/ConsulServiceInstance.cs
index 5c31174d2f..bc38ec621f 100644
--- a/src/Discovery/src/Consul/ConsulServiceInstance.cs
+++ b/src/Discovery/src/Consul/ConsulServiceInstance.cs
@@ -16,6 +16,9 @@ internal sealed class ConsulServiceInstance : IServiceInstance
///
public string ServiceId { get; }
+ ///
+ public string InstanceId { get; }
+
///
public string Host { get; }
@@ -48,6 +51,7 @@ internal ConsulServiceInstance(ServiceEntry serviceEntry)
Metadata = serviceEntry.Service.Meta.AsReadOnly();
IsSecure = serviceEntry.Service.Meta != null && serviceEntry.Service.Meta.TryGetValue("secure", out string? secureString) && bool.Parse(secureString);
ServiceId = serviceEntry.Service.Service;
+ InstanceId = serviceEntry.Service.ID;
Port = serviceEntry.Service.Port;
Uri = new Uri($"{(IsSecure ? "https" : "http")}://{Host}:{Port}");
}
diff --git a/src/Discovery/src/Consul/Registry/ConsulRegistration.cs b/src/Discovery/src/Consul/Registry/ConsulRegistration.cs
index 74c0dcf67d..3366692fdf 100644
--- a/src/Discovery/src/Consul/Registry/ConsulRegistration.cs
+++ b/src/Discovery/src/Consul/Registry/ConsulRegistration.cs
@@ -22,9 +22,7 @@ internal sealed class ConsulRegistration : IServiceInstance
///
public string ServiceId { get; }
- ///
- /// Gets the instance ID as registered by the Consul server.
- ///
+ ///
public string InstanceId { get; }
///
diff --git a/src/Discovery/src/Consul/ThisServiceInstance.cs b/src/Discovery/src/Consul/ThisServiceInstance.cs
index 6453bd6909..20717a7687 100644
--- a/src/Discovery/src/Consul/ThisServiceInstance.cs
+++ b/src/Discovery/src/Consul/ThisServiceInstance.cs
@@ -15,6 +15,9 @@ internal sealed class ThisServiceInstance : IServiceInstance
///
public string ServiceId { get; }
+ ///
+ public string InstanceId { get; }
+
///
public string Host { get; }
@@ -35,6 +38,7 @@ public ThisServiceInstance(ConsulRegistration registration)
ArgumentNullException.ThrowIfNull(registration);
ServiceId = registration.ServiceId;
+ InstanceId = registration.InstanceId;
Host = registration.Host;
IsSecure = registration.IsSecure;
Port = registration.Port;
diff --git a/src/Discovery/src/Eureka/EurekaServiceInstance.cs b/src/Discovery/src/Eureka/EurekaServiceInstance.cs
index e6ac9e1928..1a4e843073 100644
--- a/src/Discovery/src/Eureka/EurekaServiceInstance.cs
+++ b/src/Discovery/src/Eureka/EurekaServiceInstance.cs
@@ -13,6 +13,7 @@ namespace Steeltoe.Discovery.Eureka;
internal sealed class EurekaServiceInstance : IServiceInstance
{
public string ServiceId { get; }
+ public string InstanceId { get; }
public string Host { get; }
public int Port { get; }
public bool IsSecure { get; }
@@ -24,6 +25,7 @@ public EurekaServiceInstance(InstanceInfo instance)
ArgumentNullException.ThrowIfNull(instance);
ServiceId = instance.AppName;
+ InstanceId = instance.InstanceId;
Host = instance.HostName;
Port = GetPort(instance);
IsSecure = instance.IsSecurePortEnabled;
diff --git a/src/Discovery/src/HttpClients/LoadBalancers/ServiceInstancesResolver.cs b/src/Discovery/src/HttpClients/LoadBalancers/ServiceInstancesResolver.cs
index 8f354d8da2..2ea2c03c93 100644
--- a/src/Discovery/src/HttpClients/LoadBalancers/ServiceInstancesResolver.cs
+++ b/src/Discovery/src/HttpClients/LoadBalancers/ServiceInstancesResolver.cs
@@ -138,6 +138,7 @@ private sealed class JsonSerializableServiceInstance : IServiceInstance
// Trust that deserialized instances meet the IServiceInstance contract, so suppress nullability warnings.
public string ServiceId { get; set; } = null!;
+ public string InstanceId { get; set; } = null!;
public string Host { get; set; } = null!;
public int Port { get; set; }
public bool IsSecure { get; set; }
@@ -151,6 +152,7 @@ public static JsonSerializableServiceInstance CopyFrom(IServiceInstance instance
return new JsonSerializableServiceInstance
{
ServiceId = instance.ServiceId,
+ InstanceId = instance.InstanceId,
Host = instance.Host,
Port = instance.Port,
IsSecure = instance.IsSecure,
diff --git a/src/Discovery/test/Consul.Test/Discovery/ConsulDiscoveryClientTest.cs b/src/Discovery/test/Consul.Test/Discovery/ConsulDiscoveryClientTest.cs
index 88caae557d..7d1e0cb3ff 100644
--- a/src/Discovery/test/Consul.Test/Discovery/ConsulDiscoveryClientTest.cs
+++ b/src/Discovery/test/Consul.Test/Discovery/ConsulDiscoveryClientTest.cs
@@ -32,6 +32,7 @@ public async Task AddInstancesToListAsync_AddsExpected()
Service = new AgentService
{
Service = "ServiceId",
+ ID = "Instance1",
Address = "foo.bar.com",
Port = 1234,
Meta = new Dictionary
@@ -46,6 +47,7 @@ public async Task AddInstancesToListAsync_AddsExpected()
Service = new AgentService
{
Service = "ServiceId",
+ ID = "Instance2",
Address = "foo1.bar1.com",
Port = 5678,
Meta = new Dictionary
@@ -79,6 +81,7 @@ await discoveryClient.AddInstancesToListAsync(serviceInstances, "ServiceId", Que
serviceInstances[0].Host.Should().Be("foo.bar.com");
serviceInstances[0].ServiceId.Should().Be("ServiceId");
+ serviceInstances[0].InstanceId.Should().Be("Instance1");
serviceInstances[0].IsSecure.Should().BeTrue();
serviceInstances[0].Port.Should().Be(1234);
serviceInstances[0].Metadata.Should().HaveCount(2);
@@ -88,6 +91,7 @@ await discoveryClient.AddInstancesToListAsync(serviceInstances, "ServiceId", Que
serviceInstances[1].Host.Should().Be("foo1.bar1.com");
serviceInstances[1].ServiceId.Should().Be("ServiceId");
+ serviceInstances[1].InstanceId.Should().Be("Instance2");
serviceInstances[1].IsSecure.Should().BeFalse();
serviceInstances[1].Port.Should().Be(5678);
serviceInstances[1].Metadata.Should().HaveCount(2);
@@ -169,6 +173,7 @@ public async Task GetAllInstances_ReturnsExpected()
Service = new AgentService
{
Service = "ServiceId",
+ ID = "Instance1",
Address = "foo.bar.com",
Port = 1234,
Meta = new Dictionary
@@ -183,6 +188,7 @@ public async Task GetAllInstances_ReturnsExpected()
Service = new AgentService
{
Service = "ServiceId",
+ ID = "Instance2",
Address = "foo1.bar1.com",
Port = 5678,
Meta = new Dictionary
@@ -215,6 +221,7 @@ public async Task GetAllInstances_ReturnsExpected()
serviceInstances[0].Host.Should().Be("foo.bar.com");
serviceInstances[0].ServiceId.Should().Be("ServiceId");
+ serviceInstances[0].InstanceId.Should().Be("Instance1");
serviceInstances[0].IsSecure.Should().BeTrue();
serviceInstances[0].Port.Should().Be(1234);
serviceInstances[0].Metadata.Should().HaveCount(2);
@@ -224,6 +231,7 @@ public async Task GetAllInstances_ReturnsExpected()
serviceInstances[1].Host.Should().Be("foo1.bar1.com");
serviceInstances[1].ServiceId.Should().Be("ServiceId");
+ serviceInstances[1].InstanceId.Should().Be("Instance2");
serviceInstances[1].IsSecure.Should().BeFalse();
serviceInstances[1].Port.Should().Be(5678);
serviceInstances[1].Metadata.Should().HaveCount(2);
diff --git a/src/Discovery/test/Consul.Test/Discovery/ConsulServiceInstanceTest.cs b/src/Discovery/test/Consul.Test/Discovery/ConsulServiceInstanceTest.cs
index a9426cd7a2..9f23b3a233 100644
--- a/src/Discovery/test/Consul.Test/Discovery/ConsulServiceInstanceTest.cs
+++ b/src/Discovery/test/Consul.Test/Discovery/ConsulServiceInstanceTest.cs
@@ -16,6 +16,7 @@ public void Constructor_Initializes()
Service = new AgentService
{
Service = "ServiceId",
+ ID = "Instance1",
Address = "foo.bar.com",
Port = 1234,
Tags =
@@ -35,6 +36,7 @@ public void Constructor_Initializes()
serviceInstance.Host.Should().Be("foo.bar.com");
serviceInstance.ServiceId.Should().Be("ServiceId");
+ serviceInstance.InstanceId.Should().Be("Instance1");
serviceInstance.IsSecure.Should().BeTrue();
serviceInstance.Port.Should().Be(1234);
serviceInstance.Tags.Should().HaveCount(2);
diff --git a/src/Discovery/test/Consul.Test/Discovery/ThisServiceInstanceTest.cs b/src/Discovery/test/Consul.Test/Discovery/ThisServiceInstanceTest.cs
index 1b4fa260cd..e509ee6919 100644
--- a/src/Discovery/test/Consul.Test/Discovery/ThisServiceInstanceTest.cs
+++ b/src/Discovery/test/Consul.Test/Discovery/ThisServiceInstanceTest.cs
@@ -32,6 +32,7 @@ public void Constructor_Initializes()
instance.Host.Should().Be("test.foo.bar");
instance.ServiceId.Should().Be("foobar");
+ instance.InstanceId.Should().Be("ID");
instance.IsSecure.Should().BeFalse();
instance.Port.Should().Be(1234);
instance.Metadata.Should().ContainSingle();
diff --git a/src/Discovery/test/Eureka.Test/EurekaDiscoveryClientTest.cs b/src/Discovery/test/Eureka.Test/EurekaDiscoveryClientTest.cs
index fc45d1dce7..68e0e762f3 100644
--- a/src/Discovery/test/Eureka.Test/EurekaDiscoveryClientTest.cs
+++ b/src/Discovery/test/Eureka.Test/EurekaDiscoveryClientTest.cs
@@ -167,6 +167,7 @@ public async Task Constructor_Initializes_Correctly()
thisService.Metadata.Should().BeEmpty();
thisService.Port.Should().Be(5000);
thisService.ServiceId.Should().Be("DEMO");
+ thisService.InstanceId.Should().Be($"{instanceOptions.HostName}:demo:5000");
thisService.Uri.Should().Be(new Uri($"http://{instanceOptions.HostName}:5000"));
}
diff --git a/src/Discovery/test/Eureka.Test/EurekaServiceInstanceTest.cs b/src/Discovery/test/Eureka.Test/EurekaServiceInstanceTest.cs
index ce1bb62cd0..2a5403b94f 100644
--- a/src/Discovery/test/Eureka.Test/EurekaServiceInstanceTest.cs
+++ b/src/Discovery/test/Eureka.Test/EurekaServiceInstanceTest.cs
@@ -27,6 +27,7 @@ public void InstanceWithBothPorts()
var serviceInstance = new EurekaServiceInstance(instance);
serviceInstance.ServiceId.Should().Be(instance.AppName);
+ serviceInstance.InstanceId.Should().Be("id");
serviceInstance.Host.Should().Be(instance.HostName);
serviceInstance.Port.Should().Be(instance.SecurePort);
serviceInstance.IsSecure.Should().BeTrue();
diff --git a/src/Discovery/test/HttpClients.Test/LoadBalancers/RoundRobinLoadBalancerTest.cs b/src/Discovery/test/HttpClients.Test/LoadBalancers/RoundRobinLoadBalancerTest.cs
index 0d7a33fbf7..fb9d69fa7b 100644
--- a/src/Discovery/test/HttpClients.Test/LoadBalancers/RoundRobinLoadBalancerTest.cs
+++ b/src/Discovery/test/HttpClients.Test/LoadBalancers/RoundRobinLoadBalancerTest.cs
@@ -241,6 +241,7 @@ private static IDistributedCache GetCache()
private sealed class TestServiceInstance(Uri uri) : IServiceInstance
{
public string ServiceId => throw new NotImplementedException();
+ public string InstanceId => throw new NotImplementedException();
public string Host => throw new NotImplementedException();
public int Port => throw new NotImplementedException();
public bool IsSecure => throw new NotImplementedException();