From 18765cde2fba61a72b2757ddbb65851644978d12 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 13:49:02 +0000
Subject: [PATCH 1/4] Initial plan
From 936e4345d768506c7bb86f840ffe85bfc23f71d9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 27 Feb 2026 14:04:21 +0000
Subject: [PATCH 2/4] docs: add XML docs for DI Dispose/DisposeAsync explaining
async-only disposable behavior
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
---
.../src/AsyncServiceScope.cs | 23 +++++++++++++++++--
.../src/IServiceScope.cs | 12 +++++++++-
.../src/ServiceProvider.cs | 22 ++++++++++++++++--
3 files changed, 52 insertions(+), 5 deletions(-)
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
index 230ead2bd3eed9..82cded2d4883ac 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
@@ -30,13 +30,32 @@ public AsyncServiceScope(IServiceScope serviceScope)
///
public IServiceProvider ServiceProvider => _serviceScope.ServiceProvider;
- ///
+ ///
+ /// Ends the scope lifetime and disposes all resolved services.
+ ///
+ ///
+ /// Prefer calling over this method. If any resolved service implements
+ /// but not , this method throws an
+ /// (or an if multiple such
+ /// services are resolved). Use to properly handle all disposable services,
+ /// or explicitly perform sync-over-async on the caller side if synchronous disposal is required.
+ ///
+ /// A resolved service implements but not .
+ /// Multiple resolved services implement but not .
public void Dispose()
{
_serviceScope.Dispose();
}
- ///
+ ///
+ /// Asynchronously ends the scope lifetime and disposes all resolved services that implement or .
+ ///
+ ///
+ /// This is the preferred disposal method. When the underlying scope implements ,
+ /// this method handles services that implement only without throwing.
+ /// When it does not, this method falls back to calling .
+ ///
+ /// A value task that represents the asynchronous operation.
public ValueTask DisposeAsync()
{
if (_serviceScope is IAsyncDisposable ad)
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
index 148394fbb34219..0df7a1f83a5665 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
@@ -9,10 +9,20 @@ namespace Microsoft.Extensions.DependencyInjection
/// Defines a disposable service scope.
///
///
- /// The method ends the scope lifetime. Once Dispose
+ ///
+ /// The method ends the scope lifetime. Once
/// is called, any scoped services and any transient services that have been resolved from
/// will be
/// disposed.
+ ///
+ ///
+ /// If the scope implementation also implements , prefer calling
+ /// over . If
+ /// any resolved service implements but not ,
+ /// calling will throw an
+ /// (or an if multiple such services are resolved).
+ /// Consider using to ensure is always called.
+ ///
///
public interface IServiceScope : IDisposable
{
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs
index aa62e11a10be98..e66bb2ee0d6670 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs
@@ -169,14 +169,32 @@ internal object GetRequiredKeyedService(Type serviceType, object? serviceKey, Se
internal bool IsDisposed() => _disposed;
- ///
+ ///
+ /// Disposes the service provider and all resolved services that implement .
+ ///
+ ///
+ /// Prefer calling over this method. If any resolved service implements
+ /// but not , this method throws an
+ /// (or an if multiple such
+ /// services are resolved). Use to properly handle all disposable services,
+ /// or explicitly perform sync-over-async on the caller side if synchronous disposal is required.
+ ///
+ /// A resolved service implements but not .
+ /// Multiple resolved services implement but not .
public void Dispose()
{
DisposeCore();
Root.Dispose();
}
- ///
+ ///
+ /// Asynchronously disposes the service provider and all resolved services that implement or .
+ ///
+ ///
+ /// This is the preferred disposal method. Unlike , this method handles services that implement
+ /// only without throwing.
+ ///
+ /// A value task that represents the asynchronous operation.
public ValueTask DisposeAsync()
{
DisposeCore();
From 4c6d9e0c4375cdf3181b1a1c62adf61c23a745ab Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 2 Mar 2026 17:51:05 +0000
Subject: [PATCH 3/4] docs: simplify DI Dispose/DisposeAsync docs per review
feedback
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
---
.../src/AsyncServiceScope.cs | 13 +++----------
.../src/IServiceScope.cs | 3 +--
.../src/ServiceProvider.cs | 12 +++---------
3 files changed, 7 insertions(+), 21 deletions(-)
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
index 82cded2d4883ac..38009064e83e05 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
@@ -36,12 +36,10 @@ public AsyncServiceScope(IServiceScope serviceScope)
///
/// Prefer calling over this method. If any resolved service implements
/// but not , this method throws an
- /// (or an if multiple such
- /// services are resolved). Use to properly handle all disposable services,
- /// or explicitly perform sync-over-async on the caller side if synchronous disposal is required.
+ /// . Use to properly handle all
+ /// disposable services, or explicitly perform sync-over-async on the caller side if synchronous
+ /// disposal is required.
///
- /// A resolved service implements but not .
- /// Multiple resolved services implement but not .
public void Dispose()
{
_serviceScope.Dispose();
@@ -50,11 +48,6 @@ public void Dispose()
///
/// Asynchronously ends the scope lifetime and disposes all resolved services that implement or .
///
- ///
- /// This is the preferred disposal method. When the underlying scope implements ,
- /// this method handles services that implement only without throwing.
- /// When it does not, this method falls back to calling .
- ///
/// A value task that represents the asynchronous operation.
public ValueTask DisposeAsync()
{
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
index 0df7a1f83a5665..9ba59696f5fa33 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
@@ -19,8 +19,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// If the scope implementation also implements , prefer calling
/// over . If
/// any resolved service implements but not ,
- /// calling will throw an
- /// (or an if multiple such services are resolved).
+ /// calling will throw an .
/// Consider using to ensure is always called.
///
///
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs
index e66bb2ee0d6670..629b4f8c2542cb 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceProvider.cs
@@ -175,12 +175,10 @@ internal object GetRequiredKeyedService(Type serviceType, object? serviceKey, Se
///
/// Prefer calling over this method. If any resolved service implements
/// but not , this method throws an
- /// (or an if multiple such
- /// services are resolved). Use to properly handle all disposable services,
- /// or explicitly perform sync-over-async on the caller side if synchronous disposal is required.
+ /// . Use to properly handle all
+ /// disposable services, or explicitly perform sync-over-async on the caller side if synchronous
+ /// disposal is required.
///
- /// A resolved service implements but not .
- /// Multiple resolved services implement but not .
public void Dispose()
{
DisposeCore();
@@ -190,10 +188,6 @@ public void Dispose()
///
/// Asynchronously disposes the service provider and all resolved services that implement or .
///
- ///
- /// This is the preferred disposal method. Unlike , this method handles services that implement
- /// only without throwing.
- ///
/// A value task that represents the asynchronous operation.
public ValueTask DisposeAsync()
{
From e953d194c34425230e17ae960472065503866016 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Mar 2026 10:45:48 +0000
Subject: [PATCH 4/4] docs: revert DI docs changes to AsyncServiceScope and
IServiceScope
Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com>
---
.../src/AsyncServiceScope.cs | 16 ++--------------
.../src/IServiceScope.cs | 11 +----------
2 files changed, 3 insertions(+), 24 deletions(-)
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
index 38009064e83e05..230ead2bd3eed9 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs
@@ -30,25 +30,13 @@ public AsyncServiceScope(IServiceScope serviceScope)
///
public IServiceProvider ServiceProvider => _serviceScope.ServiceProvider;
- ///
- /// Ends the scope lifetime and disposes all resolved services.
- ///
- ///
- /// Prefer calling over this method. If any resolved service implements
- /// but not , this method throws an
- /// . Use to properly handle all
- /// disposable services, or explicitly perform sync-over-async on the caller side if synchronous
- /// disposal is required.
- ///
+ ///
public void Dispose()
{
_serviceScope.Dispose();
}
- ///
- /// Asynchronously ends the scope lifetime and disposes all resolved services that implement or .
- ///
- /// A value task that represents the asynchronous operation.
+ ///
public ValueTask DisposeAsync()
{
if (_serviceScope is IAsyncDisposable ad)
diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
index 9ba59696f5fa33..148394fbb34219 100644
--- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
+++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/IServiceScope.cs
@@ -9,19 +9,10 @@ namespace Microsoft.Extensions.DependencyInjection
/// Defines a disposable service scope.
///
///
- ///
- /// The method ends the scope lifetime. Once
+ /// The method ends the scope lifetime. Once Dispose
/// is called, any scoped services and any transient services that have been resolved from
/// will be
/// disposed.
- ///
- ///
- /// If the scope implementation also implements , prefer calling
- /// over . If
- /// any resolved service implements but not ,
- /// calling will throw an .
- /// Consider using to ensure is always called.
- ///
///
public interface IServiceScope : IDisposable
{