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 时抛出异常。如果它检测到错误,即使注册的依赖项永远不会在运行时得到解析,它也会抛出该异常。要查看它,请注册您的依赖项 - ServiceSample
、RepositorySample
- 就像您在单元测试中所做的那样,但不要将它们注入(inject)任何 Controller 中。当尝试构建 ServiceProvider
时,您仍然会在启动时遇到异常。
关于c# - 无法在测试中重现异常无法使用 Mvc 框架之外的单例的作用域服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60975543/