[API Proposal]: ActivatorUtilities.CreateInstance with parameter for service key
- 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
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