dotnet / dotnet/runtime

[API Proposal]: ActivatorUtilities.CreateInstance with parameter for service key

Open
#130,130 4 comments 0 reactions 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

It's currently impossible to properly activate a container-external type which uses the `ServiceKeyAttribute` and/or the `FromKeyedServicesAttribute` with `LookupMode` set to `InheritKey`, because ActivatorUtilities assumes the parent scope key to be null.

### API Proposal

```csharp
namespace Microsoft.Extensions.DependencyInjection;

public static class ActivatorUtilities
{
public static object CreateInstanceWithKey(IServiceProvider provider, Type instanceType, object? serviceKey, params object[] parameters);
public static T CreateInstanceWithKey(IServiceProvider provider, object? serviceKey, params object[] parameters);
}
```

### API Usage

```csharp
var serviceCollection = new ServiceCollection();
var serviceProvider = serviceCollection.BuildServiceProvider();

ActivatorUtilities.CreateInstanceWithKey(serviceProvider, typeof(C), "key1");
// or
ActivatorUtilities.CreateInstanceWithKey(serviceProvider, "key1");
class C([ServiceKey] object? key);
```

### Alternative Designs

### Alternative 1 - No Rename
```csharp
namespace Microsoft.Extensions.DependencyInjection;

public static class ActivatorUtilities
{
public static object CreateInstance(IServiceProvider provider, object? serviceKey, Type instanceType, params object[] parameters);
public static T CreateInstance(IServiceProvider provider, object? serviceKey, params object[] parameters);
}
```
The generic overload will conflict with an existing overload,
```cs
public static T CreateInstance(IServiceProvider provider, params object[] parameters);
```
It is possible to rearrange the parameters for the non-generic overload, but not for the generic overload, unless placing the service key before the service provider is considered.

### Alternative 2 - `CreateKeyedInstance`
I've considered the name, but I do not believe it is appropriate because the created instance and its type is not part of the container and thus it cannot be "keyed"

### Alternative 3 - Modify existing overloads
This approach introduces binary breaking changes

### Risks

- The API proposal strictly adds new APIs, but I imagine that it will touch the same code paths as the existing `CreateInstance` overloads which might introduce unobserved breaking behavioral changes.
- The new APIs complicate `ActivatorUtilities`' handling of keyed services.

Contributor guide

Open the contributing guide

Research direction

Start with the existing ActivatorUtilities.CreateInstance overloads and the keyed-service handling described in the proposal. Compare the proposed generic and non-generic signatures with the existing overloads, then examine behavior for ServiceKeyAttribute and FromKeyedServicesAttribute with LookupMode set to InheritKey. Done means an API design is selected without binary-breaking changes and the stated risks are addressed.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.