tmenier / Flurl

Fluent URL builder and testable HTTP client for .NET
https://flurl.dev
MIT License
4.21k stars 388 forks source link

Not able to configure Delegating handler in Flurl clientless DI configuration #828

Closed bjose7 closed 4 months ago

bjose7 commented 4 months ago

Flurl website document shows it has a configuration which allows to pass in Delegating Handlers. https://flurl.dev/docs/configuration/ It would be at the end of the above link.

All the below code is configured in the Program class. This is azure function app, running on isolated worker model.

While the clientless pattern in static clients format works

FlurlHttp.Clients.WithDefaults(builder => builder
    .AddMiddleware(new MyDelegatingHandler()));

Above config works.

But this DI pattern below doesnt.

// DI pattern: 
services.AddSingleton<IFlurlClientCache>(sp => new FlurlClientCache()
    .WithDefaults(builder => builder
        .AddMiddleware(sp.GetService<IMyDelegatingHandler>())

I need the DI format, because my CustomDelegationHandler has other classes injected into it and it would have been easier if the DI version worked.

Sample DelegationHandler being used:

public class MyDelegationHandler : DelegatingHandler
{
    private static string CorrelationId => "correlation-id";

    private readonly ICorrelationIdQuery _correlationIdQuery;

    public MyDelegationHandler(ICorrelationIdQuery correlationIdQuery)
    {
        _correlationIdQuery = correlationIdQuery ;
    }

    protected async override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        string correlationId = await _correlationIdQuery.Execute();

        if (!request.Headers.Contains(CorrelationId))
        {
            request.Headers.Add(CorrelationId, correlationId);
        }

        return await base.SendAsync(request, cancellationToken);
    }
}

So my code becomes:

ServiceProvider serviceProvider = services.BuildServiceProvider();
FlurlHttp.Clients.WithDefaults(builder => builder
        .AddMiddleware(() => new MyDelegationHandler(serviceProvider.GetService<ICorrelationIdQuery>())));

Above works, but not sure calling service provider like that is good idea in the Program class. This is the hostbuilder.ConfigureServices section and calling BuildServiceProvider in the middle is not good.

What can i be doing wrong in the below DI version of the code.

services.AddTransient<MyDelegationHandler>();
services.AddSingleton(sp => new FlurlClientCache()
    .WithDefaults(builder => builder
        .AddMiddleware(() => sp.GetService<MyDelegationHandler>())
    ));

https://stackoverflow.com/questions/78653878/how-to-configure-delegating-handler-in-flurl-clientless-configuration Created a stackoverflow version if anyone else had the same question. Thanks

tmenier commented 4 months ago

Not a bug, more a question of correct usage. I'll try to help on SO.

bjose7 commented 4 months ago

Thanks for the answer.