Skip to content

When parameter type has [ServiceKey] allow 'object' as the parameter type #114785

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

Merged
merged 1 commit into from
Apr 18, 2025

Conversation

steveharter
Copy link
Contributor

@steveharter steveharter commented Apr 17, 2025

When the [ServiceKey] attribute is applied to a constructor parameter (which sets the parameter value to the key that was used to resolve the service), support using object as the parameter type.

Before this PR, the parameter had to be the actual type the service is requested with, even when AnyKey is used. With this PR, the parameter can now also be object for both cases where the service is registered as the actual type or registered as AnyKey.

Supporting both cases helps decouple the service implementation from the registration key type when the service implementation elects to use object as the parameter type with [ServiceKey].

Also fixed was a validation issue when AnyKey was used with ValidateOnBuild=true which caused [ServiceKey] not to work at all even if the parameter type was the actual type.

Fixes #114780
Fixes #93438

@steveharter steveharter added this to the 10.0.0 milestone Apr 17, 2025
@steveharter steveharter self-assigned this Apr 17, 2025
@Copilot Copilot AI review requested due to automatic review settings April 17, 2025 15:26
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

Copy link
Contributor

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

// Assert
Assert.Equal(42, actualInt.Key);
Assert.Equal("hello", actualString.Key);
Assert.Null(notFound);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert.Null(notFound);

Just curious why GetKeyedService return null when using boolean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bool is not registered with AddKeyedTransient(); only int and string are.

// Act
var actualInt = serviceProvider.GetKeyedService<ServiceKeyWithObjectTypedArgument>(42);
var actualString = serviceProvider.GetKeyedService<ServiceKeyWithObjectTypedArgument>("hello");
var notFound = serviceProvider.GetKeyedService<ServiceKeyWithObjectTypedArgument>(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetKeyedService

what would be the behavior when passing null as a parameter? will GetKeyedService return null? or will return ServiceKeyWithObjectTypedArgument object with Key = null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing null means that this is not a "keyed service" so it just uses the type which is ServiceKeyWithObjectTypedArgument and since that was not registered, it returns null.

These checks are really just verifying that [ServiceKey] object key is called with the correct key and no unexpected exceptions occur.

Copy link
Member

@tarekgh tarekgh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. can you think of any breaking can happen because of this change other than allowing the object scenario that used to throw before?

@steveharter
Copy link
Contributor Author

LGTM. can you think of any breaking can happen because of this change other than allowing the object scenario that used to throw before?

No breaking changes that I can think of. This functionality is just injecting the key used, no lookups or anything, so it's fairly isolated.

@steveharter steveharter merged commit 2459e3f into dotnet:main Apr 18, 2025
77 of 87 checks passed
@steveharter steveharter deleted the DiValidateOnBuild branch April 18, 2025 15:49
@github-actions github-actions bot locked and limited conversation to collaborators May 19, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
2 participants