-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#98551 - Regression in DI scope validation #98661
Changes from all commits
4e69d52
a27fe80
03cf7ad
8c9563a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -239,6 +239,84 @@ public void GetService_DoesNotThrow_WhenGetServiceForNonScopedImplementationWith | |
Assert.NotNull(result); | ||
} | ||
|
||
[Fact] | ||
public void BuildServiceProvider_ValidateOnBuild_Throws_WhenScopedIsInjectedIntoSingleton() | ||
{ | ||
// Arrange | ||
var serviceCollection = new ServiceCollection(); | ||
serviceCollection.AddScoped<IBar, Bar>(); | ||
serviceCollection.AddSingleton<IFoo, Foo>(); | ||
|
||
// Act + Assert | ||
var aggregateException = Assert.Throws<AggregateException>(() => serviceCollection.BuildServiceProvider(new ServiceProviderOptions() { ValidateOnBuild = true, ValidateScopes = true })); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume without the fix here, that no exception was thrown here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An exception was indeed not thrown here, however it was thrown when registering the dependencies in the reversed order. The aspnet core repo happens to test the this scenario, while the runtime repo only covered the latter. This happened because in the previous code, the scoped-in-singleton check was not performed if a callsite was already cached. See here as well: #98551 (comment) |
||
Assert.StartsWith("Some services are not able to be constructed", aggregateException.Message); | ||
Assert.Equal(1, aggregateException.InnerExceptions.Count); | ||
Assert.Equal("Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+IFoo Lifetime: Singleton ImplementationType: Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+Foo': " + | ||
"Cannot consume scoped service 'Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+IBar' from singleton 'Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+IFoo'." | ||
, aggregateException.InnerExceptions[0].Message); | ||
} | ||
|
||
[Fact] | ||
public void BuildServiceProvider_ValidateOnBuild_Throws_WhenScopedIsInjectedIntoSingleton_ReverseRegistrationOrder() | ||
{ | ||
// Arrange | ||
var serviceCollection = new ServiceCollection(); | ||
serviceCollection.AddSingleton<IFoo, Foo>(); | ||
serviceCollection.AddScoped<IBar, Bar>(); | ||
|
||
// Act + Assert | ||
var aggregateException = Assert.Throws<AggregateException>(() => serviceCollection.BuildServiceProvider(new ServiceProviderOptions() { ValidateOnBuild = true, ValidateScopes = true })); | ||
Assert.StartsWith("Some services are not able to be constructed", aggregateException.Message); | ||
Assert.Equal(1, aggregateException.InnerExceptions.Count); | ||
Assert.Equal("Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+IFoo Lifetime: Singleton ImplementationType: Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+Foo': " + | ||
"Cannot consume scoped service 'Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+IBar' from singleton 'Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+IFoo'." | ||
, aggregateException.InnerExceptions[0].Message); | ||
} | ||
|
||
[Fact] | ||
public void BuildServiceProvider_ValidateOnBuild_DoesNotThrow_WhenScopeFactoryIsInjectedIntoSingleton() | ||
{ | ||
// Arrange | ||
var serviceCollection = new ServiceCollection(); | ||
serviceCollection.AddSingleton<IBoo, Boo>(); | ||
|
||
// Act + Assert | ||
serviceCollection.BuildServiceProvider(new ServiceProviderOptions() { ValidateOnBuild = true, ValidateScopes = true }); | ||
} | ||
|
||
[Fact] | ||
public void BuildServiceProvider_ValidateOnBuild_Throws_WhenScopedIsInjectedIntoSingleton_CachedCallSites() | ||
{ | ||
// Arrange | ||
var serviceCollection = new ServiceCollection(); | ||
serviceCollection.AddScoped<Foo>(); | ||
serviceCollection.AddSingleton<Foo2>(); | ||
serviceCollection.AddScoped<IBar, Bar2>(); | ||
serviceCollection.AddScoped<IBaz, Baz>(); | ||
|
||
// Act + Assert | ||
var aggregateException = Assert.Throws<AggregateException>(() => serviceCollection.BuildServiceProvider(new ServiceProviderOptions() { ValidateOnBuild = true, ValidateScopes = true })); | ||
Assert.StartsWith("Some services are not able to be constructed", aggregateException.Message); | ||
Assert.Equal(1, aggregateException.InnerExceptions.Count); | ||
Assert.Equal("Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+Foo2 Lifetime: Singleton ImplementationType: Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+Foo2': " + | ||
"Cannot consume scoped service 'Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+IBar' from singleton 'Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderValidationTests+Foo2'." | ||
, aggregateException.InnerExceptions[0].Message); | ||
} | ||
|
||
[Fact] | ||
public void BuildServiceProvider_ValidateOnBuild_DoesNotThrow_CachedCallSites() | ||
{ | ||
// Arrange | ||
var serviceCollection = new ServiceCollection(); | ||
serviceCollection.AddScoped<Foo>(); | ||
serviceCollection.AddScoped<Foo2>(); | ||
serviceCollection.AddScoped<IBar, Bar2>(); | ||
serviceCollection.AddScoped<IBaz, Baz>(); | ||
|
||
// Act + Assert | ||
serviceCollection.BuildServiceProvider(new ServiceProviderOptions() { ValidateOnBuild = true, ValidateScopes = true }); | ||
} | ||
|
||
[Fact] | ||
public void BuildServiceProvider_ValidateOnBuild_ThrowsForUnresolvableServices() | ||
{ | ||
|
@@ -327,6 +405,13 @@ public Foo(IBar bar) | |
} | ||
} | ||
|
||
private class Foo2 : IFoo | ||
{ | ||
public Foo2(IBar bar) | ||
{ | ||
} | ||
} | ||
|
||
private interface IBar | ||
{ | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benjaminpetit PTAL