![](/img/trans.png)
[英]How to override and interface and call "base" interface in ASP.NET Core built-in DI container?
[英]Replace service registration in ASP.NET Core built-in DI container?
讓我們考慮在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);
也可以看看:
如果您知道兩個簡單的事情,很容易覆蓋 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;
}
只是添加@ilya-chumakov 的好答案,這里是相同的方法,但支持實現工廠
public static IServiceCollection Replace<TService>(
this IServiceCollection services,
Func<IServiceProvider, TService> implementationFactory,
ServiceLifetime lifetime)
where TService : class
{
var descriptorToRemove = services.FirstOrDefault(d => d.ServiceType == typeof(TService));
services.Remove(descriptorToRemove);
var descriptorToAdd = new ServiceDescriptor(typeof(TService), implementationFactory, lifetime);
services.Add(descriptorToAdd);
return services;
}
如果我們想將它與實例化服務的工廠一起使用,如下例所示:
var serviceProvider =
new ServiceCollection()
.Replace<IMyService>(sp => new MyService(), ServiceLifetime.Singleton)
.BuildServiceProvider();
我替換了我的測試夾具 WebApplicationFactory 中的存儲庫使用
public static WebApplicationFactory<TEntryPoint> WithRepository<TEntryPoint>(
this WebApplicationFactory<TEntryPoint> webApplicationFactory,
IStoreRepository storeRespository)
where TEntryPoint : class
{
return webApplicationFactory.WithWebHostBuilder(builder => builder.ConfigureTestServices(
services =>
{
services.Replace(ServiceDescriptor.Scoped(p => storeRespository));
}));
}
並在測試中使用它作為
var respository = new ListRepository();
var client = _factory
.WithRepository(respository)
.CreateClient();
在最新版本的 .net core(net5.0) 中,應該是這樣。
using Microsoft.Extensions.DependencyInjection;
services.Replace<IFoo, FooB>(ServiceLifetime.Transient); // Or ServiceLifetime.Singleton
或者試試這個。
services.Replace(ServiceDescriptor.Transient<IFoo, FooB>());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.