Closed lassevk closed 8 months ago
@lassevk Let's keep this issue open until the IKeyedServiceProvider
and its friends are implemented.
IKeyedServiceProvider
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.ikeyedserviceprovider?view=dotnet-plat-ext-8.0IServiceProviderIsKeyedService
https://learn.microsoft.com/es-es/dotnet/api/microsoft.extensions.dependencyinjection.iserviceprovideriskeyedservice?view=dotnet-plat-ext-8.0FromKeyedServicesAttribute
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.fromkeyedservicesattribute?view=dotnet-plat-ext-8.0KeyedServiceAttribute
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicekeyattribute?view=dotnet-plat-ext-8.0ServiceProvider
https://github.com/dotnet/runtime/issues/64427#issuecomment-1610060118Let's address a challenge of the not-uniqueness of the MS.DI keyed services comparing to the uniqueness of DryIoc keyed services.
Create the composite key for the second, third, etc. MS key adding its index into the pair, e.g. "foo", ("foo", 1), ("foo", 2).
Pros:
Cons:
SelectLastFactory
rule to search for the duplicate keys.Represent the MS keys as DryIoc metadata
Pros:
SelectLastFactory
need to be adjusted to filter based on metadataCons:
DryIoc treats the service key as unique ID for the same service type. So it prevents you with registering the same service type with the same service key. The main question, should I use the DryIoc metadata then or can
The type of KeyedImplementationFactory
is Func<IServiceProvider, object?, object>
where the object?
parameter is the key. Specifically, it is not the registration service key but the resolution/injection key, which may differ (e.g. it may be the AnyKey
described below).
Problem is that DryIoc does not supply a service key into the FactoryDelegate
which type is Func<IResolverContext, object>
.
We need to support the KeyedService.AnyKey
to resolve the service with any (not null) service key specified.
Therefore, I will be adding Registrator.AnyServiceKey
on the DryIoc side.
So far, so good. But what is this thing? See the next section for the reveal :-P
[Fact]
public void ResolveKeyedServiceSingletonFactoryWithAnyKeyIgnoreWrongType()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddKeyedTransient<IService, ServiceWithIntKey>(KeyedService.AnyKey);
var provider = CreateServiceProvider(serviceCollection);
Assert.Null(provider.GetService<IService>());
Assert.NotNull(provider.GetKeyedService<IService>(87));
Assert.ThrowsAny<InvalidOperationException>(() => provider.GetKeyedService<IService>(new object()));
}
Marks the parameter to be injected with the resolution service key as in the following case used by the test above:
internal class ServiceWithIntKey : IService
{
private readonly int _id;
public ServiceWithIntKey([ServiceKey] int id) => _id = id;
}
In the example Service
we need to select the Constructor with key string id
for the keyed resolution and the default one for the non-keyed one.
internal class Service : IService
{
private readonly string _id;
public Service() => _id = Guid.NewGuid().ToString();
public Service([ServiceKey] string id) => _id = id;
public override string? ToString() => _id;
}
internal class OtherService
{
public OtherService(
[FromKeyedServices("service1")] IService service1,
[FromKeyedServices("service2")] IService service2)
{
Service1 = service1;
Service2 = service2;
}
public IService Service1 { get; }
public IService Service2 { get; }
}
Seems like we are doing the same Key for the same service Type in DryIoc.MefAttributedModel.
For this purpose, MEF has ServiceKeyStore
stores the map from the Key to the all types registered (exported) with this key. And if Type is the same, it increases the number of such registrations and uses this number to augment the service Key and make it unique.
Question, can we use the MEF for MS.DI?...
Probably no, but we may steal the ServiceKeyStore
or better the whole AttributedModel.WithMultipleSameContractNamesSupport
method.
Btw, how to get all non-keyed services in the collection?
//cc @yallie
Ok, for the last 2 failing tests we need the #618
@dadhi, sorry, I'm on vacation, have no PC to look into it. Will return next Monday. Moving the required code from MEF to DtryIoc core seems like a good idea 👍
@yallie Enjoy vacation, I have moved the thing already and optimized it along the way.
done
You probably have it on your radar, but if not then here is a reminder to look into expanding the support for using DryIoc as the container in applications using the Microsoft.Extensions.Hosting framework.
When .NET 8 is released, and the Microsoft.Extensions.Hosting package version 8 is released, Microsoft has finally added keyed service support. The bridge between DryIoc and IServiceCollection need to be added so that these can be used also when DryIoc is the underlying container.
The following example runs with the new hosting nuget package, but uncomment the DryIoc configuration and it throws an InvalidOperationException with the message
This service descriptor is keyed. Your service provider may not support keyed services.
.interface and classes for complete code