[API Proposal]: Scoped Service Provider Accessor
- 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
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