Description
Description
I'm trying to use the new Keyed services feature, but it looks like the KeyedService.AnyKey
piece is not functional when used in conjunction with ServiceKeyAttribute
?
E: Issue only occurs when trying to use a base class for the ServiceKeyAttribute
argument, e.g. in the case below where object
is the argument.
Whenever I try, all combination of types leads to an exception:
System.InvalidOperationException: 'The type of the key used for lookup doesn't match the type in the constructor parameter with the ServiceKey attribute.'
This appears to be due to a check that requires the parameter's type to be the same as the one on the registration:
However, this is impossible because KeyedService.AnyKey
uses a dedicated private type and is only exposed as object
.
I feel like I'm missing something here, but how does KeyedService.AnyKey
work with that strict type check in place?
Reproduction Steps
Create a new console app under .NET 8 RC2, add the Microsoft.Extensions.DependencyInjection package, and paste this into Program.cs
:
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddKeyedTransient<Service>(KeyedService.AnyKey);
// This line throws
// System.InvalidOperationException: 'The type of the key used for lookup doesn't match the type in the constructor parameter with the ServiceKey attribute.'
using var provider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
// If ValidateOnBuild is false, this line also throws
// System.InvalidOperationException: 'The type of the key used for lookup doesn't match the type in the constructor parameter with the ServiceKey attribute.'
var service = provider.GetKeyedService<Service>("test");
public class Service
{
public Service([ServiceKey] object serviceKey)
{ }
}
Expected behavior
- When using
KeyedService.AnyKey
for a service that uses the[ServiceKey]
attribute, building the service provider should succeed without validation failures - When using
KeyedService.AnyKey
for a service that uses the[ServiceKey]
attribute, resolving the service using any key input should return the registered implementation and fill in the service key value for the marked parameter
Actual behavior
In both of the above points, a System.InvalidOperationException
is thrown instead
Regression?
No response
Known Workarounds
I can workaround by using a factory service registration instead:
using Microsoft.Extensions.DependencyInjection;
var services = new ServiceCollection();
services.AddKeyedTransient<Service>(KeyedService.AnyKey, (_, key) => new Service(key));
// Validation succeeds now
using var provider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateOnBuild = true });
// Resolving service also succeeds now
var service = provider.GetKeyedService<Service>("test");
public class Service
{
public Service(object serviceKey)
{ }
}
Configuration
.NET SDK:
Version: 8.0.100-rc.2.23502.2
Commit: 0abacfc2b6
Runtime Environment:
OS Name: Windows
OS Version: 10.0.23550
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\8.0.100-rc.2.23502.2\
.NET workloads installed:
<removed for brevity>
Host:
Version: 8.0.0-rc.2.23479.6
Architecture: x64
Commit: 0b25e38ad3
.NET SDKs installed:
8.0.100-rc.2.23502.2 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
<removed for brevity>
Microsoft.NETCore.App 8.0.0-rc.2.23479.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
<removed for brevity>
Other architectures found:
x86 [C:\Program Files (x86)\dotnet]
registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]
Environment variables:
Not set
global.json file:
Not found
Learn more:
https://aka.ms/dotnet/info
Download .NET:
https://aka.ms/dotnet/download
Other information
No response