Skip to content

Update IServiceScopeFactory.CreateScope docs to clarify transient service disposal#124248

Merged
rosebyte merged 6 commits intomainfrom
copilot/update-api-docs-service-scope
Feb 13, 2026
Merged

Update IServiceScopeFactory.CreateScope docs to clarify transient service disposal#124248
rosebyte merged 6 commits intomainfrom
copilot/update-api-docs-service-scope

Conversation

Copy link
Contributor

Copilot AI commented Feb 10, 2026

Description

API documentation for IServiceScopeFactory.CreateScope and IServiceScope stated that only "scoped services" are disposed when a scope ends. This omitted the fact that transient services are also tracked and disposed by scopes, leading to confusion about scope disposal behavior.

Changes

Updated XML documentation in two files:

  • IServiceScopeFactory.cs: Updated <returns> section to specify that both scoped services and transient services are disposed
  • IServiceScope.cs: Updated <remarks> section with same clarification

The updated documentation now states:

Once this is disposed, any scoped services and any transient services that have been resolved from the ServiceProvider will be disposed.

This wording clarifies that transient services are disposed by scopes in a simple and concise manner, without explicitly mentioning disposal interface types (IDisposable/IAsyncDisposable). The simplified language addresses the core confusion raised in the original issue while keeping the documentation accessible.

This aligns with the actual DI container behavior and the guidance in Microsoft Learn documentation on disposable transient services captured by container.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Docs] Update API docs for IServiceScopeFactory.CreateScope</issue_title>
<issue_description>The API docs for IServiceScopeFactory.CreateScope state:

Returns: An IServiceScope controlling the lifetime of the scope. Once this is disposed, any scoped services that have been resolved from the IServiceScope.ServiceProvider will also be disposed.

This was a source of confusion for me as I always believed that anything created by a child scope is disposed by that child scope. Meaning it would also dispose transient services.

And elsewhere, the docs state:

When you register Transient services that implement IDisposable, by default the DI container will hold onto these references, and not Dispose() of them until the container is disposed when application stops if they were resolved from the container, or until the scope is disposed if they were resolved from a scope. This can turn into a memory leak if resolved from container level.

So the API wording should be changed to include "or transient services".</issue_description>

<agent_instructions>Improve the documentation and emphasise that transient services are tracked by DI scopes and eventually disposed when as part of the scope disposal.</agent_instructions>

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

@ericstj @lonix1 would you like to propose a PR that clarifies this? @rosebyte The tracking and eventual disposing of transient services at the end of scope should be emphasised in documentation as it may lead to astonishing situations.

💡 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.

Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
Copilot AI changed the title [WIP] Update API docs for IServiceScopeFactory.CreateScope Update IServiceScopeFactory.CreateScope docs to clarify transient service disposal Feb 10, 2026
Copilot AI requested a review from rosebyte February 10, 2026 22:23
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 10, 2026
Copilot AI and others added 2 commits February 11, 2026 10:46
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
Copilot AI requested a review from rosebyte February 11, 2026 11:56
@rosebyte rosebyte marked this pull request as ready for review February 11, 2026 12:00
Copilot AI review requested due to automatic review settings February 11, 2026 12:00
@rosebyte rosebyte enabled auto-merge (squash) February 11, 2026 12:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates XML documentation in DI Abstractions to clarify scope disposal behavior, aiming to address confusion around whether transient services resolved from a scope are disposed when the scope ends.

Changes:

  • Updated IServiceScopeFactory.CreateScope <returns> documentation to mention transient services in scope disposal.
  • Updated IServiceScope <remarks> documentation with the same clarification.

Reviewed changes

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

File Description
src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScopeFactory.cs Updates CreateScope return docs to mention transient disposal at scope end.
src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs Updates IServiceScope remarks to mention transient disposal at scope end.

@stephentoub
Copy link
Member

🤖 Copilot Code Review — PR #124248

Holistic Assessment

Motivation: The PR addresses a real documentation gap. The linked issue (#104472) describes user confusion about scope disposal behavior, particularly whether transient services are disposed. The implementation confirms that transient services implementing IDisposable/IAsyncDisposable are indeed tracked via CaptureDisposable and disposed when the scope ends. This clarification is valuable and addresses a legitimate source of confusion.

Approach: The approach of adding clarifying text to existing documentation is appropriate and low-risk. The change is minimal and focused on the stated goal.

Summary: ⚠️ Needs Human Review. The documentation change is directionally correct and addresses a real gap. However, the wording "any transient services" may be technically imprecise, as only disposable transient services are actually tracked and disposed. A human reviewer should decide whether the current wording is acceptable for consistency with existing documentation style (which also says "any scoped services" without the "disposable" qualifier), or whether precision should be prioritized.


Detailed Findings

⚠️ Technical Precision — "any transient services" vs "any disposable transient services"

Files: IServiceScope.cs (line 13), IServiceScopeFactory.cs (line 19)

The updated documentation says "any scoped services and any transient services...will be disposed." However, examining the implementation in ServiceProviderEngineScope.CaptureDisposable:

if (ReferenceEquals(this, service) || !(service is IDisposable || service is IAsyncDisposable))
{
    return service; // Non-disposable services are not captured
}

Only services implementing IDisposable or IAsyncDisposable are actually tracked and disposed. Non-disposable transient services are not captured by the scope.

However, the existing documentation already has the same pattern — it says "any scoped services...will be disposed" without the "disposable" qualifier. So the new wording is consistent with existing documentation style.

Options for consideration:

  1. Accept as-is — The word "disposed" inherently implies the service is disposable. The current wording matches the existing style and addresses the core confusion.
  2. Add "disposable" qualifier — Change to "any disposable transient services" for maximum technical precision. This would also arguably require updating "any scoped services" to "any disposable scoped services" for consistency, which expands scope.

This is flagged for human judgment as it's a documentation style decision rather than a correctness bug.


✅ Implementation Verification — Transient disposal behavior is correct

The PR description's claim is accurate. Verified via implementation review:

  • ResultCache.cs: ServiceLifetime.TransientCallSiteResultCacheLocation.Dispose
  • CallSiteRuntimeResolver.VisitDisposeCache: Calls CaptureDisposable for transients
  • ServiceProviderEngineScope.CaptureDisposable: Tracks disposable services
  • ServiceProviderEngineScope.Dispose/DisposeAsync: Disposes all tracked services

The DI container does track and dispose transient services resolved from a scope, which is exactly what this documentation clarifies.


💡 Suggestion — Consistency with AsyncServiceScope

The PR mentions that async disposal behavior is documented on AsyncServiceScope. For completeness, consider whether AsyncServiceScope documentation should also be updated to mention transient services, though this may be out of scope for this PR.


Cross-Cutting Analysis

I checked for similar documentation patterns in the codebase. The existing documentation style in these interfaces does not use the "disposable" qualifier when referring to services being disposed. The PR maintains consistency with this established pattern.


Summary

Severity Finding Action
⚠️ "any transient services" may be imprecise Human reviewer should decide if precision or consistency is preferred
Implementation supports the claim No action needed
💡 AsyncServiceScope consistency Consider for follow-up

Verdict: ⚠️ Needs Human Review — The change is fundamentally correct and addresses a real documentation gap. The precision question ("any transient services" vs "any disposable transient services") is a style/consistency decision that requires maintainer judgment. Given that the existing documentation already uses "any scoped services" without the "disposable" qualifier, accepting as-is for consistency is reasonable.


Multi-model review synthesis: Claude Opus, GPT-5.2, and Gemini 3 Pro all flagged the precision issue. All agreed the change is directionally correct but noted the wording could be more precise.

@cincuranet cincuranet added area-Extensions-DependencyInjection and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 12, 2026
@cincuranet cincuranet added this to the 11.0.0 milestone Feb 12, 2026
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-dependencyinjection
See info in area-owners.md if you want to be subscribed.

@rosebyte rosebyte merged commit 1ad784f into main Feb 13, 2026
90 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Docs] Update API docs for IServiceScopeFactory.CreateScope

4 participants