首页 > 解决方案 > 无法在测试中重现异常无法从 Mvc 框架外的单例中使用范围服务

问题描述

InvalidOperationException Cannot consume scoped service from singleton是一个众所周知的场景,这里描述得很好

我正在研究一种重现此异常的方法(假设它来自依赖注入框架),但我没有成功。

创建了一个带有提交的 repo 来说明它,但基本上我有以下测试:

public class Given_Scoped_Repository_And_Singleton_Service_That_Uses_The_Repository_When_Getting_Service_From_Different_Scope_After_Disposing_First_Scope
    : Given_When_Then_Test
{
    private IServiceScope _scopeOne;
    private IServiceScope _scopeTwo;
    private ServiceSample _serviceSampleOne;
    private ServiceSample _serviceSampleTwo;

    protected override void Given()
    {
        var serviceCollection =
            new ServiceCollection()
                .AddScoped<RepositorySample>()
                .AddSingleton<ServiceSample>()
                .BuildServiceProvider();

        _scopeOne = serviceCollection.CreateScope();
        _scopeTwo = serviceCollection.CreateScope();

        _serviceSampleOne = _scopeOne.ServiceProvider.GetService<ServiceSample>();

        _scopeOne.Dispose();
    }

    protected override void When()
    {
        _serviceSampleTwo = _scopeTwo.ServiceProvider.GetService<ServiceSample>();
    }

    [Fact]
    public void Then_It_Should_Get_The_Same_Service_Instance()
    {
        _serviceSampleOne.Should().Be(_serviceSampleTwo);
    }

    [Fact]
    public void Then_It_Should_Have_The_Same_Repository_Instance()
    {
        _serviceSampleOne.RepositorySample.Should().Be(_serviceSampleTwo.RepositorySample);
    }
}

class RepositorySample { }
class ServiceSample
{
    public RepositorySample RepositorySample { get; }

    public ServiceSample(RepositorySample repositorySample)
    {
        RepositorySample = repositorySample;
    }
}

我希望看到这个InvalidOperationException抛出,因为我从不同的范围获得一个单例服务,期望存储库是不同的(因为它是范围的)。即使我明确地处理了实例化范围的第一个上下文,这些测试也没有失败RepositorySample,我在这里有点困惑。

标签: c#dependency-injection

解决方案


它没有抛出异常,因为尚未指定验证范围的选项。

改变这个:

.BuildServiceProvider();

对此:

.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true });

ServiceProviderOptions.ValidateScopes

true 执行检查以验证范围内的服务永远不会从根提供者处得到解析;

您还可以在ServiceProvider构建时执行验证,而不是等到服务解决:

.BuildServiceProvider(
    new ServiceProviderOptions
    {
        ValidateScopes = true,
        ValidateOnBuild = true
    });

这就是 MVC 应用程序在启动时所做的事情。这就是为什么在启动时抛出异常,而不是在解析控制器时抛出异常。如果它检测到错误,即使注册的依赖项在运行时永远不会被解析,它也会抛出该异常。要查看它,请注册您的依赖项 - ServiceSample, RepositorySample- 就像您在单元测试中所做的那样,但不要将它们注入任何控制器。尝试构建ServiceProvider.


推荐阅读