Skip to content

Fix: transient disposable detection misses IAsyncDisposable-only services - #33

Merged
AGiorgetti merged 3 commits into
developfrom
copilot/fix-transient-disposable-detection
Feb 27, 2026
Merged

Fix: transient disposable detection misses IAsyncDisposable-only services#33
AGiorgetti merged 3 commits into
developfrom
copilot/fix-transient-disposable-detection

Conversation

Copilot AI commented Feb 26, 2026

Copy link
Copy Markdown
Contributor
  • Fix PatchForDetectIncorrectUsageOfTransientDisposables to check IAsyncDisposable in open generic check
  • Fix PatchForDetectIncorrectUsageOfTransientDisposables switch case for type-based descriptors to check IAsyncDisposable
  • Fix CreatePatchedFactoryDescriptor to detect IAsyncDisposable at runtime
  • Fix CreatePatchedKeyedFactoryDescriptor to detect IAsyncDisposable at runtime
  • Add private IsDisposableType helper to avoid repetition
  • Add TransientAsyncDisposable, AsyncDisposableConsumer, AsyncDisposableConsumerFactory test fixtures
  • Add test: resolving IAsyncDisposable-only transient from root scope with validation throws
  • Add test: resolving IAsyncDisposable-only transient from a child scope with validation does not throw (with GetDisposables assertions)
  • Add test: factory-registered IAsyncDisposable-only service from root scope with validation throws
  • Add test: factory-registered IAsyncDisposable-only service from child scope does not throw (with GetDisposables assertions)
  • Add test: keyed IAsyncDisposable-only transient from root scope with validation throws
  • Add test: keyed factory IAsyncDisposable-only service from root scope with validation throws
  • All 30 transient disposable tests pass on net8.0, net9.0, net10.0
Original prompt

This section details on the original issue you should resolve

<issue_title>Bug: Transient disposable detection misses IAsyncDisposable-only services</issue_title>
<issue_description>## Description

In DetectIncorrectUsageOfTransientDisposables.cs, the transient disposable detection only checks for typeof(IDisposable).IsAssignableFrom(...). Services that implement only IAsyncDisposable (without IDisposable) will leak from the root scope undetected.

Example

// Current code only checks IDisposable:
if (typeof(IDisposable).IsAssignableFrom(descriptor.ImplementationType))

// But a service like this would be missed:
public class MyAsyncService : IAsyncDisposable
{
    public ValueTask DisposeAsync() { /* cleanup */ }
}

Impact

Services implementing only IAsyncDisposable that are registered as transient will not trigger the diagnostic exception when resolved from the root scope, potentially causing memory leaks — the exact scenario this detection feature is designed to prevent.

Suggested Fix

Check both interfaces:

typeof(IDisposable).IsAssignableFrom(type) || typeof(IAsyncDisposable).IsAssignableFrom(type)

This applies to multiple locations in PatchForDetectIncorrectUsageOfTransientDisposables and related patching methods.</issue_description>

<agent_instructions>write tests to confirm the issue and the resolution</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…able

Co-authored-by: AGiorgetti <246067+AGiorgetti@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix detection of IAsyncDisposable-only transient services Fix: transient disposable detection misses IAsyncDisposable-only services Feb 26, 2026
@AGiorgetti
AGiorgetti marked this pull request as ready for review February 27, 2026 09:17
Copilot AI review requested due to automatic review settings February 27, 2026 09:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes a bug in the transient disposable detection feature where services implementing only IAsyncDisposable (without IDisposable) were not detected, potentially causing memory leaks when resolved from the root scope.

Changes:

  • Introduced IsDisposableType helper method that checks both IDisposable and IAsyncDisposable interfaces
  • Updated all registration-time type checks to use the new helper method
  • Updated all runtime checks in factory descriptors to detect both disposal interfaces
  • Added comprehensive test coverage for IAsyncDisposable-only services including type-based, factory-based, and keyed service scenarios

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/Mammoth.Extensions.DependencyInjection/DetectIncorrectUsageOfTransientDisposables.cs Added IsDisposableType helper and updated all disposable type checks to cover both IDisposable and IAsyncDisposable
src/Mammoth.Extensions.DependencyInjection.Tests/DetectIncorrectUsageOfTransientDisposablesTests.cs Added test fixtures and six test methods covering type-based, factory-based, and keyed scenarios for IAsyncDisposable-only services

@AGiorgetti

Copy link
Copy Markdown
Contributor

@copilot apply changes based on the comments in this thread

Co-authored-by: AGiorgetti <246067+AGiorgetti@users.noreply.github.com>
@AGiorgetti
AGiorgetti changed the base branch from main to develop February 27, 2026 09:40
@AGiorgetti
AGiorgetti merged commit de64b7d into develop Feb 27, 2026
1 check passed
@AGiorgetti
AGiorgetti deleted the copilot/fix-transient-disposable-detection branch February 27, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Transient disposable detection misses IAsyncDisposable-only services

3 participants