Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot register nested generic interface in .NET Core

I am trying to register the nested generic type in DI container, but unable to register

throws {Open generic service type requires registering an open generic implementation type. (Parameter descriptors)} error

Implemented Interface method looks like:

public class CustomerEvent<TEntity> : IEventConsumer<EntityInsertedEvent<TEntity>>,
    IEventConsumer<EntityUpdatedEvent<TEntity>>,
    IEventConsumer<EntityDeletedEvent<TEntity>> where TEntity : BaseEntity
{
    public void HandleEvent(EntityInsertedEvent<TEntity> eventMessage)
    {
        throw new NotImplementedException("Inserted");
    }

    public void HandleEvent(EntityUpdatedEvent<TEntity> eventMessage)
    {
        throw new NotImplementedException("Updated");
    }

    public void HandleEvent(EntityDeletedEvent<TEntity> eventMessage)
    {
        throw new NotImplementedException("Deleted");
    }
}

Tried

Assembly.GetExecutingAssembly()
    .GetTypes()
    .Where(item => item.GetInterfaces()
    .Where(i => i.IsGenericType)
        .Any(i => i.GetGenericTypeDefinition() == typeof(IEventConsumer<>))
            && !item.IsAbstract && !item.IsInterface)
    .ToList().ForEach(assignedTypes =>
    {
        assignedTypes.GetInterfaces()
            .Where(i => i.GetGenericTypeDefinition() == typeof(IEventConsumer<>)).ToList()
            .ForEach(imp =>
            {
                services.AddScoped(imp, assignedTypes);
            });
    });

but failed

like image 404
Sanjeeb Avatar asked May 15 '26 19:05

Sanjeeb


1 Answers

There is no easy way to do this. Typically, you need to map an open-generic abstraction to an open-generic implementation, like this:

services.AddTransient(typeof(IEventConsumer<>), typeof(CustomerEvent<>));

This, however, will not work in your case because MS.DI is unable to figure out how the generic type argument for IEventCustomer<T> should maps to the generic type argument of CustomerEvent<TEntity>. When resolving an IEventCustomer<EntityInsertedEvent<Order>>, for instance, it will try to create a CustomerEvent<EntityInsertedEvent<Order>>, while it should have been creating a CustomerEvent<Order>.

This is not a limitation of .NET or the CLR, but a limitation that is specific to the MS.DI DI Container, because some other DI Containers are actually able to make these kinds of mappings.

Unfortunately, with MS.DI, there is no easy way out. The only thing you can do is making all possible closed-generic registrations explicitly, e.g.:

s.AddTransient<IEventConsumer<EntityInsertedEvent<Order>>, CustomerEvent<Order>>();
s.AddTransient<IEventConsumer<EntityInsertedEvent<Customer>>, CustomerEvent<Customer>>();
s.AddTransient<IEventConsumer<EntityInsertedEvent<Product>>, CustomerEvent<Product>>();
s.AddTransient<IEventConsumer<EntityInsertedEvent<Employee>>, CustomerEvent<Employee>>();
s.AddTransient<IEventConsumer<EntityInsertedEvent<etc>>, CustomerEvent<etc>>();
like image 167
Steven Avatar answered May 18 '26 07:05

Steven