ASP.NET Core DI:如果作用域服务同时注册为服务类型和实现类型,则解析相同的实例

4

假设我有一个服务,我想要将其解析为作用域生命周期。但是有时我尝试将其解析为接口类型,有时又尝试解析为实现类型。

我尝试做的第一件事是这样的:

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 { }
}

4
为什么您要进行实现的注册? - Camilo Terevinto
@CamiloTerevinto 虽然我同意这不是最佳实践。但我正在处理一个古老而且相当庞大的代码库,其中实现被注入到许多地方。目前无法将其更改为接口。 - Nick Muller
1个回答

6

一种选择是创建自己的扩展方法,将您在问题中展示的两行代码封装起来。例如:

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,因为编译器会自动推断它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接