ipjohnson / Grace

Grace is a feature rich dependency injection container library
MIT License
336 stars 33 forks source link

Cannot resolve generic type #238

Closed davidkeaveny closed 4 years ago

davidkeaveny commented 4 years ago

I am experiencing the following issue when using Grace 7.0.0 (and Grace.DependencyInjection.Extensions 7.0.1) with an ASP.NET Core 2.2 API:

Consider the following code:

public class CqrsDispatcher : ICqrsDispatcher
{
    private readonly IServiceProvider _serviceProvider;

    public CqrsDispatcher(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public async Task Execute<TCommand>(TCommand command) where TCommand : ICommand
    {
        var handler = (ICommandHandler<TCommand>) _serviceProvider.GetService(typeof(ICommandHandler<TCommand>));
        if (handler == null)
        {
            throw new NoHandlerForCommandException(typeof(TCommand));
        }

        await handler.Handle(command);
    }
}

as it stands, when I run the Execute method, I am getting a null value returned from the call to the IServiceProvider, which obviously triggers the exception and boom! If I add a breakpoint and inspect the IServiceProvider, I can see that Grace has successfully registered the expected class to its interface; and if I go to the Immediate window in VS and try invoking the IServiceProvider.GetService(Type) method directly using the non-generic form, then it returns the expected instance from Grace:

_serviceProvider.GetService(typeof(ICommandHandler<MyProject.Commands.MakeMoneyCommand>))
-- returns an instance of MakeMoneyCommandHandler

So why does the generic type call not return the expected instance?

ipjohnson commented 4 years ago

Hmmm that's odd, would it be possible to create a sample app to show this behavior as it doesn't make any sense?

davidkeaveny commented 4 years ago

I'll see what I can do...

davidkeaveny commented 4 years ago

Never mind, I tracked it down - in the CqrsController which invokes the ICqrsDispatcher, I was using the following:

protected virtual Task Execute(ICommand command, CancellationToken cancellationToken)
{
    return _dispatcher.Execute(command, cancellationToken);
}

instead of:

protected virtual Task Execute<TCommand>(TCommand command, CancellationToken cancellationToken) where TCommand : ICommand
{
    return _dispatcher.Execute(command, cancellationToken);
}

so Grace was trying to resolve ICommandHandler<ICommand> instead of ICommandHandler<MakeMoneyCommand>. Face, meet palm.