Skip to content

[API Proposal]: Add Type parameter overload to Microsoft.Extensions.DependencyInjection resolver delegate method #102970

Open
@thomhurst

Description

@thomhurst

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

Metadata

Metadata

Assignees

Labels

api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-Extensions-DependencyInjectionneeds-further-triageIssue has been initially triaged, but needs deeper consideration or reconsideration

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions