假设我有一个服务,我想在限定的生命周期内解决。但有时我尝试将其解析为接口(interface)类型,有时是实现类型。
我尝试做的第一件事是:
ServiceCollection services;
services.AddScoped<MyClass>();
services.AddScoped<IMyInterface, MyClass>();
上述示例的问题在于,如果我解析 IMyInterface 而不是解析 MyClass,则会使用不同的实例。基本上 2 个作用域实例可能同时存在。
我通过以下方式解决了这个问题。但它非常容易出错,因为您很容易忘记在一个地方执行此操作,而且很难注意到。
serviceCollection.AddScoped<MyClass>();
serviceCollection.AddScoped<IMyInterface, MyClass>(sp => sp.GetRequiredService<MyClass>());
有什么方法可以以不易出错的方式完成我想要的事情。最好(但不一定)在一次注册中?
即作为 xUnit 测试:
public class Tests
{
[Fact]
public void ReturnsSameInstanceForImplementationAndServiceType()
{
var serviceCollection = new ServiceCollection();
// TODO: Change these lines so they're less error prone.
serviceCollection.AddScoped<MyClass>();
serviceCollection.AddScoped<IMyInterface, MyClass>(sp => sp.GetRequiredService<MyClass>());
var services = serviceCollection.BuildServiceProvider();
var myInt = services.GetRequiredService<IMyInterface>();
var myCls = services.GetRequiredService<MyClass>();
Assert.Equal(myCls, myInt);
}
class MyClass : IMyInterface { }
interface IMyInterface { }
}
最佳答案
一种选择是创建您自己的扩展方法,该方法包含您在问题中显示的两行。例如:
public static class ServiceCollectionExtensions
{
public static void AddScopedInterfaceAndClass<TInterface, TClass>(this IServiceCollection serviceCollection)
where TInterface : class
where TClass : class, TInterface
{
serviceCollection.AddScoped<TClass>();
serviceCollection.AddScoped<TInterface, TClass>(sp => sp.GetRequiredService<TClass>());
}
}
你可以这样调用它:
serviceCollection.AddScopedInterfaceAndClass<IMyInterface, MyClass>();
我知道 AddScopedInterfaceAndClass
不是完美的名称 - 它只是一个演示该想法的示例。此外,还有一个缺点是您必须记住使用此扩展而不是AddScoped
。
注意:您可以通过删除第二个泛型 (TClass
) 来简化扩展方法中的第二个 AddScoped
,因为这是由编译器推断的。
关于c# - ASP.NET 核心 DI : Resolve same instance if scoped service is registered both as service type and implementation type,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47677504/