Search code examples
c#genericssystem.reflectionsimple-injector

Checking if IoC registrations implement command or query interfaces, and returning the generic parameter


I am using the SimpleInjector IoC container and trying to wire-up functionality on application start-up (the container will report what command-handlers and query-handlers it has registered, and we will register the commands and queries that were registered as generic types):

var suppportedCommands = new List<Type>();
var container = Bootstrapper.SimpleInjectorContainer;

foreach (var registration in container.GetCurrentRegistrations())
{
    var type = registration.ServiceType;

    var isCommandHandler = type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICommandHandler<>));

    if (isCommandHandler )
    {
        suppportedCommands.Add(type.GetGenericArguments().First());
    }
}

Although the registrations are returned correctly I don't seem to be able to:

  1. Check if it is type that implements ICommandHandler<SetUserStatusToVerifiedCommand>

  2. If it is, get the generic argument so we can keep track of commands we support

As an example, when I break-point on the returned registration that has the type SetUserStatusToVerifiedCommandHandler, the isCommandHandler variable is always false and the type string is shown as:

{Name = "ICommandHandler`1" FullName = "MyApp.ICommandHandler`1[[MyApp.Application.UserStatus.SetUserStatusToVerifiedCommand, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}`

And my interfaces and command handlers implemented as:

public interface ICommand
{
}

class SetUserStatusToVerifiedCommand : ICommand
{
    string UserId;
    DateTime VerifiedOn;
}

class SetUserStatusToVerifiedCommandHandler : ICommandHandler<SetUserStatusToVerifiedCommand>
{
    public void Handle(SetUserStatusToVerifiedCommand commandToHandle)
    {
    }
}

Any ideas what I am doing wrong please?

As a sidenote, if there is any simpler way to achieve the above with SimpleInjector advice would be appreciated.


Solution

  • The problem is in this statement:

    var type = registration.ServiceType;
    var isCommandHandler = type.GetInterfaces().Any(x => x.IsGenericType 
        && x.GetGenericTypeDefinition() == typeof(ICommandHandler<>));
    

    The Type.GetInterfaces() method returns the list of all interfaces that a certain type implements. But the registration.ServiceType will be a closed-generic version of ICommandHandler<T>. So you are basically asking what interfaces ICommandHandler<T> implements. And GetInterfaces() will not return the interface itself if called on that interface.

    So instead, you need to do this:

    var type = registration.ServiceType;
    
    var isCommandHandler = type.IsGenericType && 
        type.GetGenericTypeDefinition() == typeof(ICommandHandler<>));