From 8087e20fcc0e0c53f0466b3abe6a1a26a29fc2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Sun, 14 Sep 2025 12:40:45 -0400 Subject: [PATCH 1/4] Make serviceKey nullable for ImageGenerator Aligned with AddKeyedEmbeddingGenerator and AddKeyedChatClient. --- .../Image/ImageGeneratorBuilderServiceCollectionExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.AI/Image/ImageGeneratorBuilderServiceCollectionExtensions.cs b/src/Libraries/Microsoft.Extensions.AI/Image/ImageGeneratorBuilderServiceCollectionExtensions.cs index ec19252a319..878d6ef6b2d 100644 --- a/src/Libraries/Microsoft.Extensions.AI/Image/ImageGeneratorBuilderServiceCollectionExtensions.cs +++ b/src/Libraries/Microsoft.Extensions.AI/Image/ImageGeneratorBuilderServiceCollectionExtensions.cs @@ -55,7 +55,7 @@ public static ImageGeneratorBuilder AddImageGenerator( /// The generator is registered as a scoped service. public static ImageGeneratorBuilder AddKeyedImageGenerator( this IServiceCollection serviceCollection, - object serviceKey, + object? serviceKey, IImageGenerator innerGenerator, ServiceLifetime lifetime = ServiceLifetime.Singleton) => AddKeyedImageGenerator(serviceCollection, serviceKey, _ => innerGenerator, lifetime); @@ -70,7 +70,7 @@ public static ImageGeneratorBuilder AddKeyedImageGenerator( /// The generator is registered as a scoped service. public static ImageGeneratorBuilder AddKeyedImageGenerator( this IServiceCollection serviceCollection, - object serviceKey, + object? serviceKey, Func innerGeneratorFactory, ServiceLifetime lifetime = ServiceLifetime.Singleton) { From b99c7cab76460f5bbad55afd048d2c2b31e85179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Sun, 14 Sep 2025 13:01:31 -0400 Subject: [PATCH 2/4] Remove null check --- .../Image/ImageGeneratorBuilderServiceCollectionExtensions.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Libraries/Microsoft.Extensions.AI/Image/ImageGeneratorBuilderServiceCollectionExtensions.cs b/src/Libraries/Microsoft.Extensions.AI/Image/ImageGeneratorBuilderServiceCollectionExtensions.cs index 878d6ef6b2d..7868adf2eb3 100644 --- a/src/Libraries/Microsoft.Extensions.AI/Image/ImageGeneratorBuilderServiceCollectionExtensions.cs +++ b/src/Libraries/Microsoft.Extensions.AI/Image/ImageGeneratorBuilderServiceCollectionExtensions.cs @@ -75,7 +75,6 @@ public static ImageGeneratorBuilder AddKeyedImageGenerator( ServiceLifetime lifetime = ServiceLifetime.Singleton) { _ = Throw.IfNull(serviceCollection); - _ = Throw.IfNull(serviceKey); _ = Throw.IfNull(innerGeneratorFactory); var builder = new ImageGeneratorBuilder(innerGeneratorFactory); From 59111f00b329d809793c82b1024e1e9f461f57a4 Mon Sep 17 00:00:00 2001 From: "g.verdier" Date: Sun, 14 Sep 2025 20:07:25 +0200 Subject: [PATCH 3/4] Add test --- .../ImageGeneratorDependencyInjectionPatterns.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/Libraries/Microsoft.Extensions.AI.Tests/Image/ImageGeneratorDependencyInjectionPatterns.cs b/test/Libraries/Microsoft.Extensions.AI.Tests/Image/ImageGeneratorDependencyInjectionPatterns.cs index b65495e506b..a17cd5a5c41 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Tests/Image/ImageGeneratorDependencyInjectionPatterns.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Tests/Image/ImageGeneratorDependencyInjectionPatterns.cs @@ -154,6 +154,22 @@ public void AddKeyedImageGenerator_RegistersExpectedLifetime(ServiceLifetime? li Assert.Equal(expectedLifetime, sd.Lifetime); } + [Fact] + public void AddKeyedImageGenerator_WorksWithNullServiceKey() + { + ServiceCollection sc = new(); + sc.AddKeyedImageGenerator(null, _ => new TestImageGenerator()); + + ServiceDescriptor sd = Assert.Single(sc); + Assert.Equal(typeof(IImageGenerator), sd.ServiceType); + Assert.False(sd.IsKeyedService); + Assert.Null(sd.ServiceKey); + Assert.Null(sd.ImplementationInstance); + Assert.NotNull(sd.ImplementationFactory); + Assert.IsType(sd.ImplementationFactory(null!)); + Assert.Equal(ServiceLifetime.Singleton, sd.Lifetime); + } + public class SingletonMiddleware(IImageGenerator inner, IServiceProvider services) : DelegatingImageGenerator(inner) { public new IImageGenerator InnerGenerator => base.InnerGenerator; From befee3be1e1a9d9ba8b3e3cbc31322dd306bdf25 Mon Sep 17 00:00:00 2001 From: "g.verdier" Date: Sun, 14 Sep 2025 20:45:00 +0200 Subject: [PATCH 4/4] Same for SpeechToTextClient --- ...xtClientBuilderServiceCollectionExtensions.cs | 5 ++--- ...echToTextClientDependencyInjectionPatterns.cs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Libraries/Microsoft.Extensions.AI/SpeechToText/SpeechToTextClientBuilderServiceCollectionExtensions.cs b/src/Libraries/Microsoft.Extensions.AI/SpeechToText/SpeechToTextClientBuilderServiceCollectionExtensions.cs index 5ef54e8db26..243cb057068 100644 --- a/src/Libraries/Microsoft.Extensions.AI/SpeechToText/SpeechToTextClientBuilderServiceCollectionExtensions.cs +++ b/src/Libraries/Microsoft.Extensions.AI/SpeechToText/SpeechToTextClientBuilderServiceCollectionExtensions.cs @@ -52,7 +52,7 @@ public static SpeechToTextClientBuilder AddSpeechToTextClient( /// The client is registered as a scoped service. public static SpeechToTextClientBuilder AddKeyedSpeechToTextClient( this IServiceCollection serviceCollection, - object serviceKey, + object? serviceKey, ISpeechToTextClient innerClient, ServiceLifetime lifetime = ServiceLifetime.Singleton) => AddKeyedSpeechToTextClient(serviceCollection, serviceKey, _ => innerClient, lifetime); @@ -66,12 +66,11 @@ public static SpeechToTextClientBuilder AddKeyedSpeechToTextClient( /// The client is registered as a scoped service. public static SpeechToTextClientBuilder AddKeyedSpeechToTextClient( this IServiceCollection serviceCollection, - object serviceKey, + object? serviceKey, Func innerClientFactory, ServiceLifetime lifetime = ServiceLifetime.Singleton) { _ = Throw.IfNull(serviceCollection); - _ = Throw.IfNull(serviceKey); _ = Throw.IfNull(innerClientFactory); var builder = new SpeechToTextClientBuilder(innerClientFactory); diff --git a/test/Libraries/Microsoft.Extensions.AI.Tests/SpeechToText/SpeechToTextClientDependencyInjectionPatterns.cs b/test/Libraries/Microsoft.Extensions.AI.Tests/SpeechToText/SpeechToTextClientDependencyInjectionPatterns.cs index 07596a1bb6f..5595e1c82ce 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Tests/SpeechToText/SpeechToTextClientDependencyInjectionPatterns.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Tests/SpeechToText/SpeechToTextClientDependencyInjectionPatterns.cs @@ -154,6 +154,22 @@ public void AddKeyedSpeechToTextClient_RegistersExpectedLifetime(ServiceLifetime Assert.Equal(expectedLifetime, sd.Lifetime); } + [Fact] + public void AddKeyedSpeechToTextClient_WorksWithNullServiceKey() + { + ServiceCollection sc = new(); + sc.AddKeyedSpeechToTextClient(null, _ => new TestSpeechToTextClient()); + + ServiceDescriptor sd = Assert.Single(sc); + Assert.Equal(typeof(ISpeechToTextClient), sd.ServiceType); + Assert.False(sd.IsKeyedService); + Assert.Null(sd.ServiceKey); + Assert.Null(sd.ImplementationInstance); + Assert.NotNull(sd.ImplementationFactory); + Assert.IsType(sd.ImplementationFactory(null!)); + Assert.Equal(ServiceLifetime.Singleton, sd.Lifetime); + } + public class SingletonMiddleware(ISpeechToTextClient inner, IServiceProvider services) : DelegatingSpeechToTextClient(inner) { public new ISpeechToTextClient InnerClient => base.InnerClient;