让我们考虑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);
Remove(ServiceDescriptor)
合同中有IServiceCollection
个方法。我应该如何处理ServiceDescriptor
修改服务注册?
答案 0 :(得分:31)
使用Replace(IServiceCollection, ServiceDescriptor)
类中的ServiceCollectionDescriptorExtensions
方法很简单。
// IFoo -> FooA
services.AddTransient<IFoo, FooA>();
// Replace
// IFoo -> FooB
var descriptor =
new ServiceDescriptor(
typeof(IFoo),
typeof(FooB),
ServiceLifetime.Transient);
services.Replace(descriptor);
另见:
答案 1 :(得分:21)
如果你知道两件简单的事情,很容易覆盖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;
}
答案 2 :(得分:1)
只需添加@ ilya-chumakov的好答案,这是相同的方法,但支持实现工厂
var serviceProvider =
new ServiceCollection()
.Replace<IMyService>(sp => new MyService(), ServiceLifetime.Singleto)
.BuildServiceProvider();
如果我们想将其与实例化服务的工厂一起使用,例如以下示例:
{{1}}
答案 3 :(得分:-1)
在最新版本的.net core(net5.0)中,应该是这样的。
using Microsoft.Extensions.DependencyInjection;
services.Replace<IFoo, FooB>(ServiceLifetime.Transient); // Or ServiceLifetime.Singleton
或者试试这个。
services.Replace(ServiceDescriptor.Transient<IFoo, FooB>());