Skip to content

[Breaking change]: Fix issues in GetKeyedService() and GetKeyedServices() with AnyKey #49885

@ericstj

Description

@ericstj

Description

The behavior of GetKeyedService() and GetKeyedServices() methods in the Microsoft.Extensions.DependencyInjection library has been updated to address inconsistencies in handling the AnyKey registration. Specifically:

  1. Behavioral Change: The GetKeyedService() method now throws an exception when attempting to resolve a single service using KeyedService.AnyKey as the lookup key.
  2. Behavioral Change: The GetKeyedServices() method no longer returns AnyKey registrations when queried with KeyedService.AnyKey.

These changes were introduced to improve consistency in the behavior of keyed service resolution and align with the intended semantics of KeyedService.AnyKey.

Version

.NET 10 Preview 3

Previous behavior

  1. GetKeyedService(KeyedService.AnyKey):

    • Previously, calling GetKeyedService() with KeyedService.AnyKey would return a service registration associated with AnyKey. This behavior was inconsistent with the intended semantics, as AnyKey is meant to represent a special case of keyed services rather than a specific registration.
  2. GetKeyedServices(KeyedService.AnyKey):

    • Previously, calling GetKeyedServices() with KeyedService.AnyKey would return all registrations for AnyKey. This behavior was inconsistent with the intended semantics, as AnyKey is not meant to enumerate all keyed services.

New behavior

  1. GetKeyedService(KeyedService.AnyKey):

    • Calling GetKeyedService() with KeyedService.AnyKey now throws an exception. This ensures that AnyKey cannot be used to resolve a single service, as it is intended to represent a special case rather than a specific key.

    Example:

    var service = serviceProvider.GetKeyedService(typeof(IMyService), KeyedService.AnyKey);
    // Throws InvalidOperationException: "Cannot resolve a single service using AnyKey."
  2. GetKeyedServices(KeyedService.AnyKey):

    • Calling GetKeyedServices() with KeyedService.AnyKey no longer returns registrations for AnyKey. Instead, it adheres to the updated semantics where AnyKey is treated as a special case and does not enumerate services.

    Example:

    var services = serviceProvider.GetKeyedServices(typeof(IMyService), KeyedService.AnyKey);
    // Returns an empty collection.

Type of breaking change

  • Binary incompatible: Existing binaries might encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
  • Source incompatible: When recompiled using the new SDK or component or targeting the new runtime, existing source code might require source changes to compile successfully.
  • Behavioral change: Existing binaries might behave differently at runtime.

Reason for change

The previous behavior of GetKeyedService() and GetKeyedServices() with KeyedService.AnyKey was inconsistent with the intended semantics of AnyKey. The changes were introduced to:

  1. Ensure that AnyKey is treated as a special case and cannot be used to resolve a single service.
  2. Prevent GetKeyedServices() from returning AnyKey registrations when queried with AnyKey.

These updates improve the predictability and correctness of the Microsoft.Extensions.DependencyInjection library's behavior when working with keyed services.

Recommended action

Developers using GetKeyedService() or GetKeyedServices() with KeyedService.AnyKey should review their code and update it as follows:

  1. For GetKeyedService(KeyedService.AnyKey):

    • Replace calls to GetKeyedService() with KeyedService.AnyKey with specific keys or alternative logic to handle service resolution.

    Before:

    var service = serviceProvider.GetKeyedService(typeof(IMyService), KeyedService.AnyKey);

    After:

    // Replace AnyKey with a specific key or implement custom logic for service resolution.
    var service = serviceProvider.GetKeyedService(typeof(IMyService), specificKey);
  2. For GetKeyedServices(KeyedService.AnyKey):

    • Update code to explicitly enumerate or query services by specific keys instead of relying on AnyKey.

    Before:

    var services = serviceProvider.GetKeyedServices(typeof(IMyService), KeyedService.AnyKey);

    After:

    // Replace AnyKey with specific keys or implement custom logic for service enumeration.
    var services = serviceProvider.GetKeyedServices(typeof(IMyService), specificKey);

Feature area

  • Extensions

Affected APIs

  • Microsoft.Extensions.DependencyInjection.ServiceProvider.GetKeyedService(Type, object)
  • Microsoft.Extensions.DependencyInjection.ServiceProvider.GetKeyedServices(Type, object)

Additional Notes

This change was introduced in .NET 10 Preview 3. Developers targeting earlier versions of .NET are unaffected. For more details, see the pull request and the associated merge commit.

Finally, please email a link to this breaking change issue to .NET Breaking Change Notifications.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions