Repository navigation
Add regression tests for the multiple-container-build behaviour behind Func<IHub> #5645
Description
Problem Statement
The hub is registered in DI as Func<IHub> returning () => HubAdapter.Instance, rather than as an IHub, and SentryMiddleware dereferences it per request (var hub = _getHub();). That shape exists for a specific reason that nothing in the test suite currently pins.
It came from #157, which fixed #103: users were getting ObjectDisposedException: Cannot access a disposed object. Object name: 'SentryClient' on every capture in ASP.NET Core apps. The cause was a second, throwaway container — either one the app builds itself, e.g.
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();or the intermediary container ASP.NET Core builds and disposes (aspnet/Hosting#1499, by design).
Before #157 the hub was a DI singleton and OptionalHub's constructor called SentrySdk.UseHub. So each container build produced a hub and pointed the SDK at it; disposing the throwaway container disposed that hub and its client, while the real container's consumers still held the injected instance. #157 changed the contract to "never capture a hub; always dereference the current global hub at the point of use".
That behaviour is unpinned. #157 shipped without a regression test — it only adjusted two existing test files for the new constructor signature. Nothing in the suite builds a second container and asserts that captures still work. OptionalHub is long gone, and the reason the registration looks the way it does is now only discoverable from 2019 git history.
That matters right now because several things in flight touch exactly this code:
- Add a non-logging way to initialise Sentry in generic host apps #5572 (a host-level init path for generic-host apps) will add another caller of this plumbing.
- feat(mel)!: the Microsoft.Extensions.Logging integration no longer initializes the SDK #5595 changes who registers the hub accessor, and had to make the initializing registration authoritative because a
TryAddrace could silently disable the SDK. - There's a live question of whether the logging integration should register hub plumbing at all, or only its logger providers.
Any of those could reintroduce #103 without a single test failing.
Solution Brainstorm
Add regression tests, ideally before restructuring this area, covering at least:
- Throwaway container. Call
services.BuildServiceProvider()and resolve something from it, dispose it, then build the real provider and capture an event. Assert the event reaches the transport, i.e. noObjectDisposedException. This is the Failure to capture event: System.ObjectDisposedException: Cannot access a disposed object. #103 repro reduced to a test. - No captured instance. Assert the DI-resolved
IHubfollowsSentrySdk's current hub rather than an instance captured at injection time — for example, resolve it, swap the hub withSentrySdk.UseHub, and confirm the previously resolved reference now reaches the new hub. This is whatFunc<IHub>plusHubAdapterbuys, and it's what a well-meaning simplification to a singletonIHubwould silently break. - Lifetime. Assert
IHub/ISentryClientare not registered as singletons holding a concrete hub, so container disposal can never dispose the SDK's hub.
Sentry.AspNetCore.Tests is the natural home for the first, since the original report was ASP.NET Core; the second and third belong in Sentry.Extensions.Logging.Tests next to ServiceCollectionExtensions.
Worth adding a short comment at the registration itself pointing at #103, so the next person to simplify it knows what it's defending.
Activity
linear-code commentedon Sep 29, 2026
NET-832
test: pin the multiple-container behaviour behind Func<IHub> (getsent…