Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API Proposal]: the keyed service registration serviceKey non-nullable #90322

Closed
WeihanLi opened this issue Aug 10, 2023 · 6 comments
Closed
Assignees
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-Extensions-DependencyInjection question Answer questions and provide assistance, not an issue with source code or documentation.
Milestone

Comments

@WeihanLi
Copy link
Contributor

WeihanLi commented Aug 10, 2023

Background and motivation

Currently, the serviceKey in the keyed service registration extensions could be null, while when the serviceKey is null it would not be a keyed service. It feels strange that the behavior is not as its naming.

For example:

var serviceCollection = new ServiceCollection();
// reg1
serviceCollection.AddKeyedSingleton<IIdGenerator, GuidIdGenerator>(null);
// reg2
serviceCollection.AddSingleton<IIdGenerator, GuidIdGenerator>();

these two service registrations would be the same, they would add the same ServiceDescriptor like below

{
  "ServiceType": "typeof(IIdGenerator)",
  "ImplementType": "typeof(GuidIdGenerator)",
  "ServiceKey": null,
  "Lifetime": "Singleton"
  // ...
}

And the api approved serviceKey seemed to be non-nullable

#64427 (comment)

API Proposal

For namespace Microsoft.Extensions.DependencyInjection:

namespace Microsoft.Extensions.DependencyInjection;
public static class ServiceCollectionServiceExtensions {

-        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object? serviceKey);
+        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object serviceKey);
-        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object? serviceKey, Type implementationType);
+        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object serviceKey, Type implementationType);
-        public static IServiceCollection AddKeyedScoped<TService, TImplementation>(this IServiceCollection services, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedScoped<TService, TImplementation>(this IServiceCollection services, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedScoped<TService, TImplementation>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedScoped<TService, TImplementation>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedScoped<TService>(this IServiceCollection services, object? serviceKey) where TService : class;
+        public static IServiceCollection AddKeyedScoped<TService>(this IServiceCollection services, object serviceKey) where TService : class;
-        public static IServiceCollection AddKeyedScoped<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static IServiceCollection AddKeyedScoped<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;

-        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object? serviceKey);
+        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object serviceKey);
-        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object? serviceKey, Type implementationType);
+        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object serviceKey, Type implementationType);
-        public static IServiceCollection AddKeyedSingleton<TService, TImplementation>(this IServiceCollection services, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedSingleton<TService, TImplementation>(this IServiceCollection services, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedSingleton<TService, TImplementation>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedSingleton<TService, TImplementation>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedSingleton<TService>(this IServiceCollection services, object? serviceKey) where TService : class;
+        public static IServiceCollection AddKeyedSingleton<TService>(this IServiceCollection services, object serviceKey) where TService : class;
-        public static IServiceCollection AddKeyedSingleton<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static IServiceCollection AddKeyedSingleton<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;

-        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object? serviceKey);
+        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object serviceKey);
-        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object? serviceKey, Type implementationType);
+        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object serviceKey, Type implementationType);
-        public static IServiceCollection AddKeyedTransient<TService, TImplementation>(this IServiceCollection services, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedTransient<TService, TImplementation>(this IServiceCollection services, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedTransient<TService, TImplementation>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedTransient<TService, TImplementation>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedTransient<TService>(this IServiceCollection services, object? serviceKey) where TService : class;
+        public static IServiceCollection AddKeyedTransient<TService>(this IServiceCollection services, object serviceKey) where TService : class;
-        public static IServiceCollection AddKeyedTransient<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static IServiceCollection AddKeyedTransient<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;

}

For namespace Microsoft.Extensions.DependencyInjection.Extensions:

namespace Microsoft.Extensions.DependencyInjection.Extensions {
     public static class ServiceCollectionDescriptorExtensions {
-        public static IServiceCollection RemoveAllKeyed(this IServiceCollection collection, Type serviceType, object? serviceKey);
+        public static IServiceCollection RemoveAllKeyed(this IServiceCollection collection, Type serviceType, object serviceKey);
-        public static IServiceCollection RemoveAllKeyed<T>(this IServiceCollection collection, object? serviceKey);
+        public static IServiceCollection RemoveAllKeyed<T>(this IServiceCollection collection, object serviceKey);

-        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object? serviceKey);
+        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object serviceKey);
-        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object? serviceKey, Type implementationType);
+        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object serviceKey, Type implementationType);
-        public static void TryAddKeyedScoped<TService, TImplementation>(this IServiceCollection collection, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static void TryAddKeyedScoped<TService, TImplementation>(this IServiceCollection collection, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static void TryAddKeyedScoped<TService>(this IServiceCollection collection, object? serviceKey) where TService : class;
+        public static void TryAddKeyedScoped<TService>(this IServiceCollection collection, object serviceKey) where TService : class;
-        public static void TryAddKeyedScoped<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static void TryAddKeyedScoped<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;


-        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object? serviceKey);
+        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object serviceKey);
-        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object? serviceKey, Type implementationType);
+        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object serviceKey, Type implementationType);
-        public static void TryAddKeyedSingleton<TService, TImplementation>(this IServiceCollection collection, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static void TryAddKeyedSingleton<TService, TImplementation>(this IServiceCollection collection, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static void TryAddKeyedSingleton<TService>(this IServiceCollection collection, object? serviceKey) where TService : class;
+        public static void TryAddKeyedSingleton<TService>(this IServiceCollection collection, object serviceKey) where TService : class;
-        public static void TryAddKeyedSingleton<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static void TryAddKeyedSingleton<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;


-        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object? serviceKey);
+        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object serviceKey);
-        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object? serviceKey, Type implementationType);
+        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object serviceKey, Type implementationType);
-        public static void TryAddKeyedTransient<TService, TImplementation>(this IServiceCollection collection, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static void TryAddKeyedTransient<TService, TImplementation>(this IServiceCollection collection, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static void TryAddKeyedTransient<TService>(this IServiceCollection collection, object? serviceKey) where TService : class;
+        public static void TryAddKeyedTransient<TService>(this IServiceCollection collection, object serviceKey) where TService : class;
-        public static void TryAddKeyedTransient<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static void TryAddKeyedTransient<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;

     }
 }
namespace Microsoft.Extensions.DependencyInjection;

public interface IKeyedServiceProvider : IServiceProvider
{
-    object? GetKeyedService(Type serviceType, object? serviceKey);
+    object? GetKeyedService(Type serviceType, object serviceKey);
-    object GetRequiredKeyedService(Type serviceType, object? serviceKey);
+    object GetRequiredKeyedService(Type serviceType, object serviceKey);
}

API Usage

var serviceCollection = new ServiceCollection();

// throw `ArgumentNullException` since the `serviceKey` could not be null
serviceCollection.AddKeyedSingleton<IIdGenerator, GuidIdGenerator>(null);

Alternative Designs

Treat as KeyedService.AnyKey when the serviceKey is null?

Risks

No response

@WeihanLi WeihanLi added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Aug 10, 2023
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Aug 10, 2023
@ghost
Copy link

ghost commented Aug 10, 2023

Tagging subscribers to this area: @dotnet/area-extensions-dependencyinjection
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and motivation

Currently, the serviceKey in the keyed service registration extensions could be null, while when the serviceKey is null it would not be a keyed service. It's a little strange that the behavior is not as its naming.

For example:

var serviceCollection = new ServiceCollection();
// reg1
serviceCollection.AddKeyedSingleton<IIdGenerator, GuidIdGenerator>(null);
// reg2
serviceCollection.AddSingleton<IIdGenerator, GuidIdGenerator>();

these two service registrations would be the same, they would add the same ServiceDescriptor like below

{
  "ServiceType": "typeof(IIdGenerator)",
  "ImplementType": "typeof(GuidIdGenerator)",
  "ServiceKey": null,
  "Lifetime": "Singleton"
  // ...
}

API Proposal

For namespace Microsoft.Extensions.DependencyInjection:

namespace Microsoft.Extensions.DependencyInjection;
public static class ServiceCollectionServiceExtensions {

-        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object? serviceKey);
+        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object serviceKey);
-        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object? serviceKey, Type implementationType);
+        public static IServiceCollection AddKeyedScoped(this IServiceCollection services, Type serviceType, object serviceKey, Type implementationType);
-        public static IServiceCollection AddKeyedScoped<TService, TImplementation>(this IServiceCollection services, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedScoped<TService, TImplementation>(this IServiceCollection services, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedScoped<TService, TImplementation>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedScoped<TService, TImplementation>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedScoped<TService>(this IServiceCollection services, object? serviceKey) where TService : class;
+        public static IServiceCollection AddKeyedScoped<TService>(this IServiceCollection services, object serviceKey) where TService : class;
-        public static IServiceCollection AddKeyedScoped<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static IServiceCollection AddKeyedScoped<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;

-        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object? serviceKey);
+        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object serviceKey);
-        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object? serviceKey, Type implementationType);
+        public static IServiceCollection AddKeyedSingleton(this IServiceCollection services, Type serviceType, object serviceKey, Type implementationType);
-        public static IServiceCollection AddKeyedSingleton<TService, TImplementation>(this IServiceCollection services, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedSingleton<TService, TImplementation>(this IServiceCollection services, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedSingleton<TService, TImplementation>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedSingleton<TService, TImplementation>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedSingleton<TService>(this IServiceCollection services, object? serviceKey) where TService : class;
+        public static IServiceCollection AddKeyedSingleton<TService>(this IServiceCollection services, object serviceKey) where TService : class;
-        public static IServiceCollection AddKeyedSingleton<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static IServiceCollection AddKeyedSingleton<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;

-        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object? serviceKey);
+        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object serviceKey);
-        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object? serviceKey, Type implementationType);
+        public static IServiceCollection AddKeyedTransient(this IServiceCollection services, Type serviceType, object serviceKey, Type implementationType);
-        public static IServiceCollection AddKeyedTransient<TService, TImplementation>(this IServiceCollection services, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedTransient<TService, TImplementation>(this IServiceCollection services, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedTransient<TService, TImplementation>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
+        public static IServiceCollection AddKeyedTransient<TService, TImplementation>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
-        public static IServiceCollection AddKeyedTransient<TService>(this IServiceCollection services, object? serviceKey) where TService : class;
+        public static IServiceCollection AddKeyedTransient<TService>(this IServiceCollection services, object serviceKey) where TService : class;
-        public static IServiceCollection AddKeyedTransient<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static IServiceCollection AddKeyedTransient<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;

}

For namespace Microsoft.Extensions.DependencyInjection.Extensions:

namespace Microsoft.Extensions.DependencyInjection.Extensions {
     public static class ServiceCollectionDescriptorExtensions {
-        public static IServiceCollection RemoveAllKeyed(this IServiceCollection collection, Type serviceType, object? serviceKey);
+        public static IServiceCollection RemoveAllKeyed(this IServiceCollection collection, Type serviceType, object serviceKey);
-        public static IServiceCollection RemoveAllKeyed<T>(this IServiceCollection collection, object? serviceKey);
+        public static IServiceCollection RemoveAllKeyed<T>(this IServiceCollection collection, object serviceKey);

-        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object? serviceKey);
+        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object serviceKey);
-        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object? serviceKey, Type implementationType);
+        public static void TryAddKeyedScoped(this IServiceCollection collection, Type service, object serviceKey, Type implementationType);
-        public static void TryAddKeyedScoped<TService, TImplementation>(this IServiceCollection collection, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static void TryAddKeyedScoped<TService, TImplementation>(this IServiceCollection collection, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static void TryAddKeyedScoped<TService>(this IServiceCollection collection, object? serviceKey) where TService : class;
+        public static void TryAddKeyedScoped<TService>(this IServiceCollection collection, object serviceKey) where TService : class;
-        public static void TryAddKeyedScoped<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static void TryAddKeyedScoped<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;


-        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object? serviceKey);
+        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object serviceKey);
-        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object? serviceKey, Type implementationType);
+        public static void TryAddKeyedSingleton(this IServiceCollection collection, Type service, object serviceKey, Type implementationType);
-        public static void TryAddKeyedSingleton<TService, TImplementation>(this IServiceCollection collection, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static void TryAddKeyedSingleton<TService, TImplementation>(this IServiceCollection collection, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static void TryAddKeyedSingleton<TService>(this IServiceCollection collection, object? serviceKey) where TService : class;
+        public static void TryAddKeyedSingleton<TService>(this IServiceCollection collection, object serviceKey) where TService : class;
-        public static void TryAddKeyedSingleton<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static void TryAddKeyedSingleton<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;


-        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object? serviceKey);
+        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object serviceKey);
-        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object? serviceKey, Func<IServiceProvider, object, object> implementationFactory);
+        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object serviceKey, Func<IServiceProvider, object, object> implementationFactory);
-        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object? serviceKey, Type implementationType);
+        public static void TryAddKeyedTransient(this IServiceCollection collection, Type service, object serviceKey, Type implementationType);
-        public static void TryAddKeyedTransient<TService, TImplementation>(this IServiceCollection collection, object? serviceKey) where TService : class where TImplementation : class, TService;
+        public static void TryAddKeyedTransient<TService, TImplementation>(this IServiceCollection collection, object serviceKey) where TService : class where TImplementation : class, TService;
-        public static void TryAddKeyedTransient<TService>(this IServiceCollection collection, object? serviceKey) where TService : class;
+        public static void TryAddKeyedTransient<TService>(this IServiceCollection collection, object serviceKey) where TService : class;
-        public static void TryAddKeyedTransient<TService>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;
+        public static void TryAddKeyedTransient<TService>(this IServiceCollection services, object serviceKey, Func<IServiceProvider, object, TService> implementationFactory) where TService : class;

     }
 }

API Usage

var serviceCollection = new ServiceCollection();

// throw `ArgumentNullException` since the `serviceKey` could not be null
serviceCollection.AddKeyedSingleton<IIdGenerator, GuidIdGenerator>(null);

Alternative Designs

No response

Risks

No response

Author: WeihanLi
Assignees: -
Labels:

api-suggestion, untriaged, area-Extensions-DependencyInjection

Milestone: -

@steveharter
Copy link
Member

I believe the rationale here was that this API can be used for both keyed- and nonkeyed-services.

@steveharter steveharter added question Answer questions and provide assistance, not an issue with source code or documentation. and removed untriaged New issue has not been triaged by the area owner labels Aug 10, 2023
@steveharter steveharter added this to the 8.0.0 milestone Aug 10, 2023
@WeihanLi
Copy link
Contributor Author

I believe the rationale here was that this API can be used for both keyed- and nonkeyed-services.

Since we already have API for non-keyed service, think maybe we could disable null for keyed service, and it would be confusing whether null is a valid serviceKey, whether the KeyedService.AnyKey would be fallback service registration for null

@steveharter
Copy link
Member

Supporting null for the keyed services API was discussed and approved during the API review and is not likely to be changed; I'll let @benjaminpetit comment further.

@WeihanLi
Copy link
Contributor Author

But from the API approved here, seemed to be non-nullable

#64427 (comment)

@steveharter
Copy link
Member

But from the API approved here, seemed to be non-nullable

Correct that was the original proposal, but the API was changed (with internal email approval) during implementation.

@ghost ghost locked as resolved and limited conversation to collaborators Sep 21, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-Extensions-DependencyInjection question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

3 participants