mardi 26 janvier 2021

How to auto-register a generic interface to non generic implementations of that interface with Unity

I have a pattern going in my app.

public interface ICommandService<TCommand>
{
    public void Execute(TCommand command);
}

This interface is implemented by many different service classes. Here is an example:

public class UpdateWidgetService : ICommandService<UpdateWidget>
{
    public void Execute(UpdateWidget command)
    {
        ...
    }

}

public class UpdateWidget
{
    ...data
}

These service classes are being depended upon in controllers and other classes:

public class WidgetController
{
    private readonly ICommandService<UpdateWidget> service;
    
    public WidgetController(ICommandService<UpdateWidget> service)
    {
        this.service = service;
    }
    
    public ActionResult UpdateWidget(UpdateWidgetViewModel viewModel)
    {
        ...
        UpdateWidget command = viewModel.Command;
        this.service.Execute(command);
    }

}

If I am to register all type mappings manually I think that something like this would work:

container.RegisterType(typeof(ICommandService<UpdateWidget>), typeof(UpdateWidgetService));
container.RegisterType(typeof(ICommandService<CreateWidget>), typeof(CreateWidgetService));
container.RegisterType(typeof(ICommandService<DeleteGizmo>), typeof(DeleteGizmoService));
container.RegisterType(typeof(ICommandService<LaunchNuclearStrike>), typeof(LaunchNuclearStrikeService));

But as you can see there is a convention where all classes that implement ICommandService<TCommand> are named [TCommand]Service and I would really like to setup some kind of auto-registration by convention. Nothing I have tried so far as worked. My problem seems to be mainly with the generic type argument. Here is what I have so far:

var container = new UnityContainer();
var assembly = Assembly.GetExecutingAssembly();
var commandServices = assembly.GetTypes().Where(type => !type.IsAbstract && type.Name.EndsWith("Service") && type.GetInterfaces().Single().Name.StartsWith("ICommandService")).ToList();

foreach (var service in commandServices)
{
    var serviceInterface = service.GetInterfaces().Single();
    var genericTypeArgument = serviceInterface.GenericTypeArguments.Single();
    container.RegisterType(typeof(ICommandService<genericTypeArgument>), service);
}

I'm getting the following error: "'genericTypeArgument' is a variable but is used like a type".





Aucun commentaire:

Enregistrer un commentaire