dotnet / dotnet/runtime

[API Proposal]: Scoped Service Provider Accessor

Open
#130,169 9 comments 1 reaction 0 assignees View on GitHub
api-suggestion area-Extensions-DependencyInjection
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Background and motivation

In modern .NET applications, developers heavily rely on dependency injection (DI) scopes to manage the lifetime of resources per operation (e.g., handling a web request, processing a message queue item, or executing a background task). While ASP.NET Core provides `IHttpContextAccessor` to access the current HTTP context and its associated `RequestServices` ambiently, .NET lacks a generic, runtime-agnostic mechanism to access the active `IServiceProvider` scope outside of web environments.

This limitation frequently causes architectural pain points in non-web applications (such as Worker Services, Console Apps, or any Generic Host), or when writing infrastructure libraries that span both web and non-web contexts. For example:

- **Cross-Lifetime Consumption**: A Singleton service needs to process contextual data or interact with a stateful Scoped service, but it is invoked from deep within a scoped execution pipeline where passing `IServiceProvider` explicitly through method signatures is impossible or highly intrusive.
- **Library Authoring**: Infrastructure components need to ambiently fetch services from the active scope without forcing application code to manually flow the container down the call stack.

Providing a built-in `IScopedServiceProviderAccessor` powered by `AsyncLocal` resolves these issues. It standardizes ambient scope tracking natively within `Microsoft.Extensions.DependencyInjection`, bringing parity to non-web hosting environments and eliminating the need for developers to repeatedly implement custom, error-prone thread-local or async-local tracking wrappers.

### API Proposal

```csharp
namespace Microsoft.Extensions.DependencyInjection;

///
/// Provides access to the current scope , if one is available.
///
public interface IScopedServiceProviderAccessor
{
///
/// Gets or sets the current scope . Returns if there is no active scope.
///
IServiceProvider? ServiceProvider { get; set; }
}
```

### API Usage

```csharp
public class SingletonService(IScopedServiceProviderAccessor scopeAccessor)
{
private readonly IScopedServiceProviderAccessor _scopeAccessor = scopeAccessor;

public void DoSomething()
{
// Effortlessly retrieve the caller's scoped provider instance
var scopedProvider = _scopeAccessor.ServiceProvider;

if (scopedProvider is not null)
{
// Resolve scoped service specific to this call execution flow
var currentUser = scopedProvider.GetRequiredService();
}
}
}
```

### Alternative Designs

_No response_

### Risks

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with the proposed IScopedServiceProviderAccessor in the Microsoft.Extensions.DependencyInjection namespace and the AsyncLocal scope-tracking idea. No implementation files or tests are named; done would require an agreed API and behavior for exposing active scopes in web and non-web hosting contexts.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.