Skip to content

Add regression tests for the multiple-container-build behaviour behind Func<IHub> #5645

Closed

Description

@jamescrosswell

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:

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. no ObjectDisposedException. 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 IHub follows SentrySdk's current hub rather than an instance captured at injection time — for example, resolve it, swap the hub with SentrySdk.UseHub, and confirm the previously resolved reference now reaches the new hub. This is what Func<IHub> plus HubAdapter buys, and it's what a well-meaning simplification to a singleton IHub would silently break.
  • Lifetime. Assert IHub/ISentryClient are 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.

Related: #103, #157, #5572, #5595

Activity

  1. linear-code commented on Sep 29, 2026

    @linear-code
  2. added a commit that references this issue on Oct 5, 2026
    38a3d14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    .NETPull requests that update .net code

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions