dotnet-sdk icon indicating copy to clipboard operation
dotnet-sdk copied to clipboard

Best way to create a Dapr HttpClient with custom delegating handler?

Open andyfurniss4 opened this issue 1 year ago • 6 comments

I have been wondering how to use DaprClient.CreateInvokeHttpClient when I have my own HTTP delegating handler in use. My custom http handler will get and add an auth token to outgoing requests.

I'd prefer to avoid having Dapr-specific code all over my codebase so I'm trying to use Dapr in conjunction with an IHttpClientFactory. I've created a simple IHttpClientFactory implementation which just calls DaprClient.CreateInvokeHttpClient and I've registered my delegating handler against the named HttpClient service registration. However, after digging into the Dapr code, I can see that it's just hard-coded to use an InvocationHandler and there's no way to change this. So, my custom handler gets lost and never added to the HttpClient created by DaprClient.CreateInvokeHttpClient.

I cam across this issue from a few years ago which proposed resolving this by allowing consumers to pass a custom handler to DaprClient.CreateInvokeHttpClient: https://github.com/dapr/dotnet-sdk/issues/647, but it was rejected with what I think is the suggestion to just manually create your own HttpClient with your own http handler, presumably with the Dapr InvocationHandler as it's internal handler? Is this correct? I could just copy/paste the code from DaprClient.CreateInvokeHttpClient and tweak the http handler bit, but then I have to maintain this and watch for any changes the Dapr team might make in future. This seems somewhat risky. Obviously, as mentioned in the other issue, InvoationHandler is public, so I can create that and set it as the internal handler of my own custom handler, but what about the code within the DaprClient.CreateInvokeHttpClient itself (setting DaprEndpoint, building and setting the user agent, settings base address etc)? This could change at any time and suddenly Dapr could break when upgrading the NuGet version, because maybe there's some new header or something that's expected.

image

Maybe the above scenario is unlikely, but frankly I have no idea what could change in future and even if it's not likely to happen, it still feels pretty ugly.

Any ideas/suggestions?

andyfurniss4 avatar May 22 '24 13:05 andyfurniss4

@andyfurniss4 I'd think I'd be ok with an additional, optional, argument to CreateInvokeHttpClient() that allows passing a delegating handler. That seems like it would be low impact to current users but also prevent you from having to maintain the current implementation.

philliphoff avatar Jun 05 '24 23:06 philliphoff

Customizing created HTTP clients is something MSFT heavily pushed into DI-land with the use of Microsoft.Extensions.Http. Instead of new APIs to customize DaprClient, it might be much more beneficial if the recommended path forward was to resolve internal HttpClients from HttpClientFactory, tapping into the existing suite of customization already possible. I think I saw a PR here moving away from static client resolution already as well.

svengeance avatar Jun 17 '25 04:06 svengeance

Customizing created HTTP clients is something MSFT heavily pushed into DI-land with the use of Microsoft.Extensions.Http. Instead of new APIs to customize DaprClient, it might be much more beneficial if the recommended path forward was to resolve internal HttpClients from HttpClientFactory, tapping into the existing suite of customization already possible. I think I saw a PR here moving away from static client resolution already as well.

Yes, it's something I've been working towards is resolving more things from DI than static builders. I've updated many of the docs in the 1.15 release to reflect the same as well. I've got some changes planned to further improve the HttpClient experience and while I don't know if they'll make it into 1.16 for lack of time, they'll almost certainly be in the next one.

WhitWaldo avatar Jun 20 '25 11:06 WhitWaldo

@WhitWaldo Are you any closer to releasing the improvements to the HttpClient? Or do you have an update on expected release? We are looking for a better way to setting the DelegatingHandler as well, without constructing our own HttpClient. Thanks in advance!

benjaminoerskov avatar Aug 06 '25 12:08 benjaminoerskov

No, this didn't make the cut for 1.16 as I've been focusing on resolving connection issues in an upstream dependency for workflows.

Do you have any suggestions on how you'd prefer to see something like this accommodated? I'm certainly intending to move towards producing the HttpClient from an IHttpClientFactory and likely applying the various configurations there instead in a future release, but I haven't put a lot of thought into how you might configure that yourself to override the defaults, so I'm certainly open to ideas.

WhitWaldo avatar Aug 06 '25 12:08 WhitWaldo

@WhitWaldo Thank you for your quick response! All we needed to do, was to be able to set the InvocationHandler.InnerHandler so we can forward a TraceId. In order to do this, we need to construct our own HttpClient. Looking at the code @andyfurniss4 added to the discription, this worked out fine. It seems like a tedious way to achieve this though. I havent spent much time looking at this, but could a solution be to expose underlying HttpMessageHandler?

benjaminoerskov avatar Aug 06 '25 12:08 benjaminoerskov