Description
Background and motivation
If we register an open generic within the Microsoft Dependency Injection library, we have to also register the implementation as on open-generic type too:
e.g.:
services.AddSingleton(typeof(ILogger<>), typeof(MyLogger<>));
If we try and new up an object using the Func<>
overload, we get an exception.
E.g:
services.AddSingleton(typeof(ILogger<>), sp => new MyLogger(stringBuilder));
Open generic service type 'Microsoft.Extensions.Logging.ILogger`1[TCategoryName]' requires registering an open generic implementation type. (Parameter 'descriptors')
This means we're limited by how this object is created. We can't pass custom arguments to the constructor.
I propose an overload where the Func<>
also passes the Type
information to the delegate, therefore we could interrogate it and use that to create objects.
This allows for greater control over objects and more flexibility within the dependency injection setup of an application.
API Proposal
public ServiceDescriptor(
Type serviceType,
Func<IServiceProvider, Type, object> factory,
ServiceLifetime lifetime)
: this(serviceType, serviceKey: null, lifetime)
{
// Internal Microsoft DI code
}
public static IServiceCollection AddSingleton(
this IServiceCollection services,
Type serviceType,
Func<IServiceProvider, Type, object> implementationFactory)
{
// Internal Microsoft DI code
}
public static IServiceCollection AddScoped(
this IServiceCollection services,
Type serviceType,
Func<IServiceProvider, Type, object> implementationFactory)
{
// Internal Microsoft DI code
}
public static IServiceCollection AddTransient(
this IServiceCollection services,
Type serviceType,
Func<IServiceProvider, Type, object> implementationFactory)
{
// Internal Microsoft DI code
}
API Usage
var stringBuilder = new StringBuilder();
services.AddSingleton(typeof(ILogger<>), (sp, type) =>
{
// When requested `ILogger<>` is `ILogger<MyClass>` then `type` will be `typeof(ILogger<MyClass>)`
var genericLoggerType = typeof(MyLogger<>).MakeGenericType(type.GenericTypeArguments[0]);
return ActivatorUtilities.CreateInstance(sp, genericLoggerType, stringBuilder)
});
Alternative Designs
No response
Risks
No response