Considérons un enregistrement de service dans Startup.ConfigureServices
:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IFoo, FooA>();
}
Est-il possible de changer l'enregistrement de IFoo
en FooB
après l'appel de AddTransient
? Il peut être utile à des fins de test (par exemple, dans la sous-classe TestStartup
) ou si notre accès à la base de code est limité.
Si nous enregistrons une autre implémentation de IFoo
:
services.AddTransient<IFoo, FooA>();
services.AddTransient<IFoo, FooB>();
Alors GetService<IFoo>
Renvoie FooB
au lieu de FooA
:
IFoo service = services.BuildServiceProvider().GetService<IFoo>();
Assert.True(service is FooB);
Cependant, GetServices<IFoo>
Renvoie avec succès les deux implémentations (et la même chose pour GetService<IEnumerable<IFoo>>
):
var list = services.BuildServiceProvider().GetServices<IFoo>().ToList();
Assert.Equal(2, list.Count);
Il existe une méthode Remove(ServiceDescriptor)
dans le contrat IServiceCollection
. Que dois-je faire avec ServiceDescriptor
pour modifier un enregistrement de service?
C'est simple en utilisant la méthode Replace(IServiceCollection, ServiceDescriptor)
de la classe ServiceCollectionDescriptorExtensions
.
// IFoo -> FooA
services.AddTransient<IFoo, FooA>();
// Replace
// IFoo -> FooB
var descriptor =
new ServiceDescriptor(
typeof(IFoo),
typeof(FooB),
ServiceLifetime.Transient);
services.Replace(descriptor);
Voir également:
Il est facile de remplacer la fonctionnalité DI ASP.NET Core si vous savez deux choses simples:
ServiceCollection
est juste un wrapper au-dessus de List<ServiceDescriptor>
: public class ServiceCollection : IServiceCollection
{
private List<ServiceDescriptor> _descriptors = new List<ServiceDescriptor>();
}
private static IServiceCollection Add(
IServiceCollection collection,
Type serviceType,
Type implementationType,
ServiceLifetime lifetime)
{
var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime);
collection.Add(descriptor);
return collection;
}
Par conséquent, il est possible d'ajouter/supprimer des descripteurs à/de cette liste pour remplacer l'enregistrement:
IFoo service = services.BuildServiceProvider().GetService<IFoo>();
Assert.True(service is FooA);
var descriptor = services.FirstOrDefault(d => d.ServiceType == typeof(IFoo));
Assert.NotNull(descriptor);
services.Remove(descriptor);
service = services.BuildServiceProvider().GetService<IFoo>();
Assert.Null(service);
Nous finissons par Replace<TService, TImplementation>
méthode d'extension:
services.Replace<IFoo, FooB>(ServiceLifetime.Transient);
Sa mise en œuvre:
public static IServiceCollection Replace<TService, TImplementation>(
this IServiceCollection services,
ServiceLifetime lifetime)
where TService : class
where TImplementation : class, TService
{
var descriptorToRemove = services.FirstOrDefault(d => d.ServiceType == typeof(TService));
services.Remove(descriptorToRemove);
var descriptorToAdd = new ServiceDescriptor(typeof(TService), typeof(TImplementation), lifetime);
services.Add(descriptorToAdd);
return services;
}