c# - 无法在测试中重现异常无法使用 Mvc 框架之外的单例的作用域服务

标签 c# dependency-injection

InvalidOperationException 无法从单例中使用作用域服务 是一个众所周知的场景 described very well here

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

我已经created a repo with a commit to illustrate it但基本上我有以下测试:

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 的第一个上下文,我在这里有点困惑。

  • 为什么依赖注入(inject)框架 Microsoft.Extensions.DependencyInjection 3.1.3 不会抛出异常来提醒我单例范围陷阱?
  • 如果我处置第一个作用域(就好像它是 Mvc 场景中的作用域 DbContext,在发出响应时应该终止),这是否会导致 RepositorySample 实例被处置?事实并非如此,即使我让 RepositorySample 实现 IDisposable,我也可以看到作用域实例从未被释放(Dispose 方法未执行)
  • 如何设计测试来查看异常,就好像异常发生在单例服务中实例化的作用域 DbContext 中一样?

最佳答案

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

更改此:

.BuildServiceProvider();

对此:

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

ServiceProviderOptions.ValidateScopes

true to perform check verifying that scoped services never gets resolved from root provider;

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

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

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

关于c# - 无法在测试中重现异常无法使用 Mvc 框架之外的单例的作用域服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60975543/

相关文章:

c# - 无法在存储库构造函数中创建服务范围 asp.net core

javascript - 了解 AngularJS Controller 中的依赖注入(inject)

c# - 将 SqlDataSource 移动到类文件 ASP.NET

c# - 为什么 "Dispose"有效,而不是 "using(var db = new DataContext())"?

c# - Azure AD 身份验证 : Permission error while fetching access token

perl - Moose 类的依赖注入(inject)

jakarta-ee - TomEE 是如何实现依赖注入(inject)的?

c# - 如何遍历类的属性?

c# - 从服务器托管应用程序时如何获取用户文件的本地桌面路径?

c# - 将抽象工厂与 StructureMap 一起使用的可能性