Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/Discovery/src/Eureka/EurekaServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace Steeltoe.Discovery.Eureka;
public static class EurekaServiceCollectionExtensions
{
private const string SpringDiscoveryEnabled = "spring:cloud:discovery:enabled";
private const string ResolvingHttpDelegatingHandlerName = "Microsoft.Extensions.ServiceDiscovery.Http.ResolvingHttpDelegatingHandler";

/// <summary>
/// Configures to use <see cref="EurekaDiscoveryClient" /> for service discovery.
Expand Down Expand Up @@ -108,7 +109,7 @@ private static void AddEurekaClient(IServiceCollection services)
services.ConfigureCertificateOptions("Eureka");

IHttpClientBuilder eurekaHttpClientBuilder = services.AddHttpClient("Eureka");
eurekaHttpClientBuilder.ConfigureAdditionalHttpMessageHandlers((defaultHandlers, _) => RemoveDiscoveryHttpDelegatingHandler(defaultHandlers));
eurekaHttpClientBuilder.ConfigureAdditionalHttpMessageHandlers((defaultHandlers, _) => RemoveDiscoveryHttpHandlers(defaultHandlers));

eurekaHttpClientBuilder.ConfigurePrimaryHttpMessageHandler(serviceProvider =>
{
Expand All @@ -122,7 +123,7 @@ private static void AddEurekaClient(IServiceCollection services)
});

IHttpClientBuilder eurekaTokenHttpClientBuilder = services.AddHttpClient("AccessTokenForEureka");
eurekaTokenHttpClientBuilder.ConfigureAdditionalHttpMessageHandlers((defaultHandlers, _) => RemoveDiscoveryHttpDelegatingHandler(defaultHandlers));
eurekaTokenHttpClientBuilder.ConfigureAdditionalHttpMessageHandlers((defaultHandlers, _) => RemoveDiscoveryHttpHandlers(defaultHandlers));

eurekaTokenHttpClientBuilder.ConfigurePrimaryHttpMessageHandler(serviceProvider =>
{
Expand All @@ -139,12 +140,19 @@ private static void AddEurekaClient(IServiceCollection services)
services.AddSingleton<EurekaClient>();
}

private static void RemoveDiscoveryHttpDelegatingHandler(ICollection<DelegatingHandler> defaultHandlers)
private static void RemoveDiscoveryHttpHandlers(ICollection<DelegatingHandler> defaultHandlers)
{
// Prevent infinite recursion: The inner HttClient used by EurekaDiscoveryClient must not use service discovery.

DelegatingHandler[] discoveryHandlers = defaultHandlers.Where(handler =>
{
Type handlerType = handler.GetType();

if (handlerType.FullName == ResolvingHttpDelegatingHandlerName)
{
return true;
}

if (handlerType.IsConstructedGenericType)
{
Type handlerOpenType = handlerType.GetGenericTypeDefinition();
Expand All @@ -160,7 +168,6 @@ private static void RemoveDiscoveryHttpDelegatingHandler(ICollection<DelegatingH

foreach (DelegatingHandler discoveryHandler in discoveryHandlers)
{
// Prevent infinite recursion: DiscoveryHttpDelegatingHandler depends on EurekaDiscoveryClient.
defaultHandlers.Remove(discoveryHandler);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.ServiceDiscovery.Http;
using RichardSzalay.MockHttp;
using Steeltoe.Common.Discovery;
using Steeltoe.Common.Http.HttpClientPooling;
using Steeltoe.Common.TestResources;
using Steeltoe.Discovery.Consul;
using Steeltoe.Discovery.Eureka;
Expand Down Expand Up @@ -77,4 +80,34 @@ public async Task AddEurekaDiscoveryClient_WorksWithGlobalServiceDiscovery()

await action.Should().NotThrowAsync();
}

[Fact]
public async Task AddEurekaDiscoveryClient_WorksWithAspireGlobalServiceDiscovery()
{
WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create();

builder.Configuration.AddInMemoryCollection(new Dictionary<string, string?>
{
["Eureka:Client:ShouldFetchRegistry"] = "false",
["Eureka:Client:ShouldRegisterWithEureka"] = "false"
});

builder.Services.AddEurekaDiscoveryClient();
builder.Services.AddTransient<ResolvingHttpDelegatingHandler>();
builder.Services.ConfigureHttpClientDefaults(action => action.AddHttpMessageHandler<ResolvingHttpDelegatingHandler>());

var handler = new DelegateToMockHttpClientHandler();
handler.Mock.Expect(HttpMethod.Get, "http://localhost:8761/eureka/apps").Respond("application/json", "{}");

await using WebApplication host = builder.Build();

host.Services.GetRequiredService<HttpClientHandlerFactory>().Using(handler);

var discoveryClient = host.Services.GetRequiredService<EurekaDiscoveryClient>();
Func<Task> action = async () => await discoveryClient.FetchRegistryAsync(true, TestContext.Current.CancellationToken);

await action.Should().NotThrowAsync();

handler.Mock.VerifyNoOutstandingExpectation();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

#pragma warning disable IDE0130 // Namespace does not match folder structure
// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.ServiceDiscovery.Http;
#pragma warning restore IDE0130 // Namespace does not match folder structure

internal sealed class ResolvingHttpDelegatingHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
throw new InvalidOperationException("This handler should have been removed from the HttpClient pipeline.");
}
}
Loading