runtime: Customized SocketsHttpHandler does not support diagnostics tracking

I want to use custom HttpConnectionSettings for my requests since I need to decrease DefaultMaxConnectionsPerServer. As far as I know HttpConnectionSettings are only exposed when creating a new SocketsHttpHandler. However if I create a new handler with custom settings and use the handler as message handler for my HttpClient I lose my dependency tracking.

Upon debugging I noticed that the default message handler is HttpClientHandler which includes a DiagnosticsHandler that is not publicly exposed.

How can I customize HttpConnectionSettings while still seeing request diagnostics?

I don’t necessarily want to copy DiagnosticsHandler into my code to accomplish this.

On first glance I could see two possible solutions:

  1. Expose DiagnosticsHandler publicly, so consumers can wrap their custom HttpHandlers with it.
  2. Provide a way to customize HttpConnectionSettings without creating a new message handler, so consumers can use the HttpClientHandler while still being able to configure connection behavior.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 11
  • Comments: 20 (16 by maintainers)

Most upvoted comments

What about making DiagnosticsHandler public?

gRPC client will be customizing the SocketsHttpHandler and so will lose the automatic diagnostics functionality that HttpClientHandler currently offers. This isn’t a big deal because the gRPC client already has its own Activity, but I’ll need to add some logic to propagate the trace ID in the header. Copy and paste this I think.

I have fixed it in grpc-dotnet by basically duplicating all of DiagnosticsSource: grpc/grpc-dotnet#1211

FYI, AppInsights doesn’t like events it listens to being raised by multiple libraries: https://github.com/microsoft/ApplicationInsights-dotnet/issues/2194

I submitted a PR to them.

Regardless of Application Insights (or OpenTelemetry, for that matter) a tracing handler should exist to be injected via IHttpClientFactory.

Workaround: you can probably copy DiagnosticsHandler into your project. Has anyone tried that?

I have tried this and this causes other issues.

Using reflection does work:

        private static Func<SocketsHttpHandler, DelegatingHandler> CreateDiagnosticsHandlerFactory()
        {
            var diagnosticsHandler = typeof(SocketsHttpHandler).Assembly.GetType("System.Net.Http.DiagnosticsHandler");

            var ctor = diagnosticsHandler!.GetConstructors().First();
            var param = Expression.Parameter(typeof(HttpMessageHandler), "innerHandler");
            var newExp = Expression.New(ctor, param);
            var lambda = Expression.Lambda<Func<SocketsHttpHandler, DelegatingHandler>>(newExp, param);

            return lambda.Compile();
        }
var createDiagnosticsHandler= CreateDiagnosticsHandlerFactory();
var diagnosticsHandler = createDiagnosticsHandler(socketsHttpHandler);

@scalablecory Thanks for the info, I didn’t see that HttpClientHandler is customizable this way. However I would also like to adjust MaxResponseDrainSize which I can’t see as a property of HttpClientHandler.

I think that my dependency tracking is broken because DiagnosticsHandler is missing around my SocketsHttpHandler. I’m using application insights’ automatic dependency tracking that seems to integrate with the diagnostics propagated by DiagnosticsHandler.

In general I would like the freedom to adjust the settings of the SocketsHttpHandler contained in my HttpClient without losing the diagnostics. The issue I’m having is that I can’t access the SocketsHttpHandler that’s automatically created by HttpClientHandler and as explained I can’t just create a SocketsHttpHandler myself without losing diagnostic information.

I just posted this as an issue because I expected to be able to adjust the full set of HttpConnectionSettings without trade-offs like losing dependency tracking