_Startup.ConfigureServices
_でのサービス登録を考えてみましょう:
_public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IFoo, FooA>();
}
_
IFoo
が呼び出された後、FooB
登録をAddTransient
に変更することはできますか?テスト目的(たとえば、TestStartup
サブクラス)や、コードベースへのアクセスが制限されている場合に役立ちます。
別のIFoo
実装を登録する場合:
_services.AddTransient<IFoo, FooA>();
services.AddTransient<IFoo, FooB>();
_
次に、_GetService<IFoo>
_はFooB
の代わりにFooA
を返します。
_IFoo service = services.BuildServiceProvider().GetService<IFoo>();
Assert.True(service is FooB);
_
ただし、_GetServices<IFoo>
_は両方の実装を正常に返します(および_GetService<IEnumerable<IFoo>>
_についても同じです):
_var list = services.BuildServiceProvider().GetServices<IFoo>().ToList();
Assert.Equal(2, list.Count);
_
IServiceCollection
コントラクトにはRemove(ServiceDescriptor)
メソッドがあります。サービス登録を変更するには、ServiceDescriptor
をどうすればよいですか?
これは、 ServiceCollectionDescriptorExtensions
クラスの Replace(IServiceCollection, ServiceDescriptor)
メソッドを使用すると簡単です。
// IFoo -> FooA
services.AddTransient<IFoo, FooA>();
// Replace
// IFoo -> FooB
var descriptor =
new ServiceDescriptor(
typeof(IFoo),
typeof(FooB),
ServiceLifetime.Transient);
services.Replace(descriptor);
こちらもご覧ください:
次の2つの単純なことがわかっている場合、ASP.NET Core DI機能を簡単にオーバーライドできます。
ServiceCollection
は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;
}
したがって、登録を置き換えるために、このリストに記述子を追加したり、このリストから記述子を削除したりすることができます。
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);
Replace<TService, TImplementation>
拡張メソッドで終了します。
services.Replace<IFoo, FooB>(ServiceLifetime.Transient);
その実装:
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;
}