Skip to content

Commit

Permalink
Add GetKeyedService overload with Type (#105860)
Browse files Browse the repository at this point in the history
  • Loading branch information
martincostello authored Aug 21, 2024
1 parent ba8e006 commit 631778a
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ public static partial class ServiceProviderKeyedServiceExtensions
public static System.Collections.Generic.IEnumerable<object?> GetKeyedServices(this System.IServiceProvider provider, System.Type serviceType, object? serviceKey) { throw null; }
public static System.Collections.Generic.IEnumerable<T> GetKeyedServices<T>(this System.IServiceProvider provider, object? serviceKey) { throw null; }
public static T? GetKeyedService<T>(this System.IServiceProvider provider, object? serviceKey) { throw null; }
public static object? GetKeyedService(this System.IServiceProvider provider, System.Type serviceType, object? serviceKey) { throw null; }
public static object GetRequiredKeyedService(this System.IServiceProvider provider, System.Type serviceType, object? serviceKey) { throw null; }
public static T GetRequiredKeyedService<T>(this System.IServiceProvider provider, object? serviceKey) where T : notnull { throw null; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ public static class ServiceProviderKeyedServiceExtensions
throw new InvalidOperationException(SR.KeyedServicesNotSupported);
}

/// <summary>
/// Get service of type <paramref name="serviceType"/> from the <see cref="IServiceProvider"/>.
/// </summary>
/// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the service object from.</param>
/// <param name="serviceType">An object that specifies the type of service object to get.</param>
/// <param name="serviceKey">An object that specifies the key of service object to get.</param>
/// <returns>A service object of type <paramref name="serviceType"/> or null if there is no such service.</returns>
public static object? GetKeyedService(this IServiceProvider provider, Type serviceType, object? serviceKey)
{
ThrowHelper.ThrowIfNull(provider);
ThrowHelper.ThrowIfNull(serviceType);

if (provider is IKeyedServiceProvider keyedServiceProvider)
{
return keyedServiceProvider.GetKeyedService(serviceType, serviceKey);
}

throw new InvalidOperationException(SR.KeyedServicesNotSupported);
}

/// <summary>
/// Get service of type <paramref name="serviceType"/> from the <see cref="IServiceProvider"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public void ResolveKeyedService()
Assert.Null(provider.GetService<IService>());
Assert.Same(service1, provider.GetKeyedService<IService>("service1"));
Assert.Same(service2, provider.GetKeyedService<IService>("service2"));

Assert.Null(provider.GetService(typeof(IService)));
Assert.Same(service1, provider.GetKeyedService(typeof(IService), "service1"));
Assert.Same(service2, provider.GetKeyedService(typeof(IService), "service2"));
}

[Fact]
Expand All @@ -39,10 +43,12 @@ public void ResolveNullKeyedService()
var provider = CreateServiceProvider(serviceCollection);

var nonKeyed = provider.GetService<IService>();
var nullKey = provider.GetKeyedService<IService>(null);
var nullKeyOfT = provider.GetKeyedService<IService>(null);
var nullKeyOfType = provider.GetKeyedService(typeof(IService), null);

Assert.Same(service1, nonKeyed);
Assert.Same(service1, nullKey);
Assert.Same(service1, nullKeyOfT);
Assert.Same(service1, nullKeyOfType);
}

[Fact]
Expand Down Expand Up @@ -192,6 +198,7 @@ public void ResolveKeyedServiceSingletonInstance()

Assert.Null(provider.GetService<IService>());
Assert.Same(service, provider.GetKeyedService<IService>("service1"));
Assert.Same(service, provider.GetKeyedService(typeof(IService), "service1"));
}

[Fact]
Expand Down Expand Up @@ -355,6 +362,7 @@ public void ResolveKeyedServiceSingletonFactory()

Assert.Null(provider.GetService<IService>());
Assert.Same(service, provider.GetKeyedService<IService>("service1"));
Assert.Same(service, provider.GetKeyedService(typeof(IService), "service1"));
}

[Fact]
Expand Down Expand Up @@ -388,6 +396,7 @@ public void ResolveKeyedServiceSingletonFactoryWithAnyKeyIgnoreWrongType()
Assert.Null(provider.GetService<IService>());
Assert.NotNull(provider.GetKeyedService<IService>(87));
Assert.ThrowsAny<InvalidOperationException>(() => provider.GetKeyedService<IService>(new object()));
Assert.ThrowsAny<InvalidOperationException>(() => provider.GetKeyedService(typeof(IService), new object()));
}

[Fact]
Expand Down Expand Up @@ -554,6 +563,20 @@ public void ResolveKeyedTransientFromScopeServiceProvider()
Assert.NotSame(serviceA1, serviceB1);
}

[Fact]
public void ResolveKeyedServiceThrowsIfNotSupported()
{
var provider = new NonKeyedServiceProvider();
var serviceKey = new object();

Assert.Throws<InvalidOperationException>(() => provider.GetKeyedService<IService>(serviceKey));
Assert.Throws<InvalidOperationException>(() => provider.GetKeyedService(typeof(IService), serviceKey));
Assert.Throws<InvalidOperationException>(() => provider.GetKeyedServices<IService>(serviceKey));
Assert.Throws<InvalidOperationException>(() => provider.GetKeyedServices(typeof(IService), serviceKey));
Assert.Throws<InvalidOperationException>(() => provider.GetRequiredKeyedService<IService>(serviceKey));
Assert.Throws<InvalidOperationException>(() => provider.GetRequiredKeyedService(typeof(IService), serviceKey));
}

public interface IService { }

public class Service : IService
Expand Down Expand Up @@ -664,5 +687,10 @@ public interface ISimpleService { }
public class SimpleService : ISimpleService { }

public class AnotherSimpleService : ISimpleService { }

public class NonKeyedServiceProvider : IServiceProvider
{
public object GetService(Type serviceType) => throw new NotImplementedException();
}
}
}

0 comments on commit 631778a

Please sign in to comment.