[英]ASP.NET Core DI: Resolve same instance if scoped service is registered both as service type and implementation type
Say I have a service that I want to resolve with a scoped lifetime. 假设我有一个我想用scoped生命周期来解决的服务。 But sometime I try to resolve it as the interface type and sometimes at the implementation type. 但有时我尝试将其解析为接口类型,有时在实现类型。
The first thing I tried to do was this: 我试图做的第一件事是:
ServiceCollection services;
services.AddScoped<MyClass>();
services.AddScoped<IMyInterface, MyClass>();
The problem with the above sample is that a different instance is used if I resolve IMyInterface, and than resolve MyClass. 上面的示例的问题是,如果我解析IMyInterface,则使用不同的实例,而不是解析MyClass。 Basically it's possible that 2 scoped instances are alife at the same time. 基本上,两个范围的实例可能同时存在。
I work around this issue in the following way. 我通过以下方式解决此问题。 But it's very error-prone because you can easily forget to do this at one place, and it's really hard to notice. 但它很容易出错,因为你很容易忘记在一个地方做这件事,而且很难注意到。
serviceCollection.AddScoped<MyClass>();
serviceCollection.AddScoped<IMyInterface, MyClass>(sp => sp.GetRequiredService<MyClass>());
Is there any way to accomplish what I want in a way that is less error prone. 有没有办法以一种不易出错的方式完成我想要的东西。 Preferrably, but not necessarily, in a single registration? 优先,但不一定,在一次注册?
Ie as an xUnit test: 即作为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 { }
}
One option would be to create your own extension method that wraps up the two lines you've shown in your question. 一种选择是创建自己的扩展方法,将您在问题中显示的两条线包装起来。 For example: 例如:
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>());
}
}
You could call this like so: 你可以这样称呼它:
serviceCollection.AddScopedInterfaceAndClass<IMyInterface, MyClass>();
I appreciate that AddScopedInterfaceAndClass
isn't the perfect name - it's just an example to demonstrate the idea. 我很欣赏AddScopedInterfaceAndClass
不是一个完美的名字 - 它只是一个展示这个想法的例子。 Also, there is still the downside that you'd have to remember to use this extension rather then AddScoped
. 此外,还有一个缺点,你必须记住使用此扩展而不是AddScoped
。
Note: You could simplify the second AddScoped
in the extension method by removing the second generic ( TClass
) as this is inferred by the compiler. 注意:您可以简化第二AddScoped
通过移除第二通用(在扩展方法TClass
),因为这是由编译器推断。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.