reverse-proxy icon indicating copy to clipboard operation
reverse-proxy copied to clipboard

Service discovery on `MapForwarder` disabled when `httpClient` is assigned

Open RamType0 opened this issue 8 months ago • 7 comments

Describe the bug

A clear and concise description of what the bug is.

To Reproduce

  1. Make Aspire project and create Yarp project with reference to api service.
  2. Setup forwarder with following code.
var transformer = app.ServiceProvider.GetRequiredService<ITransformBuilder>().Create(transformBuilderContext
    => transformBuilderContext
    .AddPathRemovePrefix("/Api"));
#if ASSIGN_HTTP_CLIENT
var httpClient = new HttpMessageInvoker(new SocketsHttpHandler
{
    UseProxy = false,
    AllowAutoRedirect = true,
    ConnectTimeout = TimeSpan.FromSeconds(30),
});
app.MapForwarder("/Api/{**apiPath}", "https://api", ForwarderRequestConfig.Empty, transformer, httpClient);

#else
app.MapForwarder("/Api/{**apiPath}", "https://api", ForwarderRequestConfig.Empty, transformer);
#endif
  1. Access to forwarder's path and it works correctly.
  2. define ASSIGN_HTTP_CLIENT.
  3. Access to forwarder's path.
  4. It respond with error codes, and logs say "No such host".

Further technical details

  • Include the version of the packages you are using
  • Yarp.Reverse Proxy 2.3.0
  • The platform (Linux/macOS/Windows)
  • Windows 11 Pro 10.0.26100 Build 26100

RamType0 avatar May 01 '25 06:05 RamType0

IIRC Aspire sets up its own HttpClientFactory that has service discovery hooked up.

@ReubenBond - If they get an instance of HttpClient from the default HttpClientFactory, can they then set properties on it before handing to YARP.

samsp-msft avatar May 01 '25 17:05 samsp-msft

If you want to have service discovery on a custom client, you can wrap it in the same way Aspire does it for you by default: get IServiceDiscoveryHttpMessageHandlerFactory from DI and wrap your handler via CreateHandler.

MihaZupan avatar May 01 '25 17:05 MihaZupan

If you want to have service discovery on a custom client, you can wrap it in the same way Aspire does it for you by default: get IServiceDiscoveryHttpMessageHandlerFactory from DI and wrap your handler via CreateHandler.

It seems that good workaround.

But I feel that current behavior is inconsistent.

Whether service discovery is enabled on Yarp should not depend on whether httpClient has been assigned.

RamType0 avatar May 02 '25 03:05 RamType0

I see it as the same scenario as when you're using the regular IHttpClientFactory. If you add handlers to the factory, your HttpClients will have modified behavior. But if you create a new HttpClient somewhere manually without the factory, it doesn't matter how the factory was configured. Using AddHttpForwarderWithServiceDiscovery/AddServiceDiscoveryForwarderFactory is the same idea, you're only modifying the factory.

Have you tried using AddServiceDiscoveryDestinationResolver instead? I'd expect that to work regardless of how you create the client.

MihaZupan avatar May 20 '25 05:05 MihaZupan

Have you tried using AddServiceDiscoveryDestinationResolver instead? I'd expect that to work regardless of how you create the client.

How could we call AddServiceDiscoveryDestinationResolver when using IEndpointRouteBuilder.MapForwarder?

RamType0 avatar May 21 '25 04:05 RamType0

Ah yeah nvm, it wouldn't help you with MapForwarder extensions, only if you used the full config.

MihaZupan avatar May 21 '25 14:05 MihaZupan

We could add docs here (or specific to Aspire's YARP integration) to explain how to enable service discovery on custom clients. The integration could also consider adding easier ways to customize such handlers, but there's not much YARP can do out of the box to make this sort of thing "just work".

MihaZupan avatar Jun 16 '25 17:06 MihaZupan