From 180c4116077ed023562733fa7ee1fcf309ee66cd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Apr 2026 07:21:48 +0000 Subject: [PATCH 1/2] Initial plan From 0a625ab70993f5036ccffd83b5edf427bd5a4a7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Apr 2026 07:52:24 +0000 Subject: [PATCH 2/2] Fix keyed constant call-site cache identity for scope validation Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/963a10e3-de78-41ae-9ad6-60f06d54d34a Co-authored-by: rosebyte <14963300+rosebyte@users.noreply.github.com> --- .../src/ServiceLookup/ConstantCallSite.cs | 2 +- .../src/ServiceLookup/ResultCache.cs | 4 +- .../ServiceProviderValidationTests.cs | 51 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs index 979db8cffcf907..1c488d95f9a1b1 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ConstantCallSite.cs @@ -10,7 +10,7 @@ internal sealed class ConstantCallSite : ServiceCallSite private readonly Type _serviceType; internal object? DefaultValue => Value; - public ConstantCallSite(Type serviceType, object? defaultValue, object? serviceKey = null) : base(ResultCache.None(serviceType), serviceKey) + public ConstantCallSite(Type serviceType, object? defaultValue, object? serviceKey = null) : base(ResultCache.None(serviceType, serviceKey), serviceKey) { _serviceType = serviceType ?? throw new ArgumentNullException(nameof(serviceType)); if (defaultValue != null && !serviceType.IsInstanceOfType(defaultValue)) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ResultCache.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ResultCache.cs index 8cf73ab099eb3f..6651ffce05e275 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ResultCache.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ResultCache.cs @@ -8,9 +8,9 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup { internal struct ResultCache { - public static ResultCache None(Type serviceType) + public static ResultCache None(Type serviceType, object? serviceKey = null) { - var cacheKey = new ServiceCacheKey(ServiceIdentifier.FromServiceType(serviceType), 0); + var cacheKey = new ServiceCacheKey(new ServiceIdentifier(serviceKey, serviceType), 0); return new ResultCache(CallSiteResultCacheLocation.None, cacheKey); } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderValidationTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderValidationTests.cs index 3feb626c175331..aa372ce748cd56 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderValidationTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderValidationTests.cs @@ -292,6 +292,35 @@ public void ScopeValidation_ShouldBeAbleToDistingushGenericCollections_WhenGetSe Assert.IsType(actual.Last()); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void BuildServiceProvider_ValidateOnBuild_DoesNotThrow_WhenKeyedSingletonInstanceAndScopedShareServiceType(bool registerScopedFirst) + { + // Arrange + var serviceCollection = new ServiceCollection(); + if (registerScopedFirst) + { + serviceCollection.AddScoped(); + serviceCollection.AddKeyedSingleton("Key", new KeyedScopedCollisionSingletonService()); + } + else + { + serviceCollection.AddKeyedSingleton("Key", new KeyedScopedCollisionSingletonService()); + serviceCollection.AddScoped(); + } + + serviceCollection.AddSingleton(); + + // Act + Assert + using var serviceProvider = serviceCollection.BuildServiceProvider(new ServiceProviderOptions + { + ValidateScopes = true, + ValidateOnBuild = true + }); + Assert.NotNull(serviceProvider); + } + [Fact] public void GetService_DoesNotThrow_WhenScopeFactoryIsInjectedIntoSingleton() { @@ -586,5 +615,27 @@ public Boo(IServiceScopeFactory scopeFactory) { } } + + private interface IKeyedScopedCollisionService + { + } + + private class KeyedScopedCollisionSingletonService : IKeyedScopedCollisionService + { + } + + private class KeyedScopedCollisionScopedService : IKeyedScopedCollisionService + { + public KeyedScopedCollisionScopedService([FromKeyedServices("Key")] IKeyedScopedCollisionService keyedService) + { + } + } + + private class KeyedScopedCollisionOtherSingleton + { + public KeyedScopedCollisionOtherSingleton([FromKeyedServices("Key")] IKeyedScopedCollisionService keyedService) + { + } + } } }