public ActiveHandlerTrackingEntry(string name, LifetimeTrackingHttpMessageHandler handler, TimeSpan lifetime) { Name = name; Handler = handler; Lifetime = lifetime; _lock = new object(); }
// Internal for tests internal ActiveHandlerTrackingEntry CreateHandlerEntry(string name) { var services = _services; var scope = (IServiceScope)null; var options = _optionsMonitor.Get(name); if (!options.SuppressHandlerScope) { scope = _scopeFactory.CreateScope(); services = scope.ServiceProvider; } try { var builder = services.GetRequiredService <HttpMessageHandlerBuilder>(); builder.Name = name; // This is similar to the initialization pattern in: // https://github.com/aspnet/Hosting/blob/e892ed8bbdcd25a0dafc1850033398dc57f65fe1/src/Microsoft.AspNetCore.Hosting/Internal/WebHost.cs#L188 Action <HttpMessageHandlerBuilder> configure = Configure; for (var i = _filters.Length - 1; i >= 0; i--) { configure = _filters[i].Configure(configure); } configure(builder); // Wrap the handler so we can ensure the inner handler outlives the outer handler. var handler = new LifetimeTrackingHttpMessageHandler(builder.Build()); // Note that we can't start the timer here. That would introduce a very very subtle race condition // with very short expiry times. We need to wait until we've actually handed out the handler once // to start the timer. // // Otherwise it would be possible that we start the timer here, immediately expire it (very short // timer) and then dispose it without ever creating a client. That would be bad. It's unlikely // this would happen, but we want to be sure. return(new ActiveHandlerTrackingEntry(name, handler, scope, options.HandlerLifetime)); void Configure(HttpMessageHandlerBuilder b) { for (var i = 0; i < options.HttpMessageHandlerBuilderActions.Count; i++) { options.HttpMessageHandlerBuilderActions[i](b); } } } catch { // If something fails while creating the handler, dispose the services. scope?.Dispose(); throw; } }