How to scan and decorate an open generic interface used multiple times?
See original GitHub issueHello!
Let me start of by asking if my issue is possibly related to #39 , cuz I feel like it might be.
I discovered your project and I really like the possibilities it offers. I am having a tough time trying to get a functionality to work and I’d love to know if I am able to do this or not. (If I can, I’d like to know how)
My project uses commands and queries, and those commands are decorated. My controller has instances of these command/query handlers. When executing the commands, I’d like the decorators to be executed first, in order, until the actual commandhandler is executed.
A little overview of what I would like to accomplish:
public interface ICommandHandler<in TCommand> where TCommand : Command
{
Task HandleAsync(TCommand command);
}
public class Command { }
public class ExampleCommand : Command
{
public int Id {get; set; }
}
//Actual handler:
public class ExampleCommandHandler : ICommandHandler<ExampleCommand>
{
// It has a repo to retrieve data from, this would be injected in the constructor
public async Task HandleAsync(ExampleCommand command)
{
// Do stuff with the repo...
}
}
//First decorator
public class Decorator1CommandHandler : ICommandHandler<ExampleCommand>
{
private ICommandHandler<ExampleCommand> _innerHandler;
private IFunctionality<ExampleCommand> _functionality;
public Decorator1Commandhandler(...)
{
// Set properties
}
public Task HandleAsync(ExampleCommand command)
{
// Calls the functionality that this decorator is built for. This ALSO has some more dependency injection in it's constructor...
await _functionality.DoStuff(command);
// Calls the 2nd decorator
await _innerHandler.HandleAsync(command);
}
}
// 2nd decorator
public class Decorator2CommandHandler : ICommandHandler<ExampleCommand>
{
private ICommandHandler<ExampleCommand> _innerHandler;
private IOtherFunctionality<ExampleCommand> _functionality;
public Decorator2Commandhandler(...)
{
// Set properties
}
public Task HandleAsync(ExampleCommand command)
{
// Calls the functionality that this decorator is built for. This ALSO has some more dependency injection in it's constructor...
await _functionality.DoStuff(command);
// Calls the ACTUAL command handler defined above.
await _innerHandler.HandleAsync(command);
}
}
// Usage of the command stuff
public class ValuesController : BaseController
{
private readonly ICommandHandler<ExampleCommand> _commandHandler;;
//Imagine this being an endpoint, and the commandhandler being injected in the constructor
public async Task<string> Endpoint()
{
return await _commandHandler.HandleAsync(new ExampleCommand{ Id = 1});
}
}
**Startup**:
//This makes sure that every command handler is inserted in the DI container
services.Scan(scan => scan
.FromAssembliesOf(typeof(IQueryHandler<,>))
.AddClasses(classes => classes.AssignableTo(typeof(ICommandHandler<,>)))
.AsImplementedInterfaces()
.WithTransientLifetime());
//This makes sure that every command handler has its own 2 decorators registered.
services.Decorate(typeof(ICommandHandler<>), typeof(Decorator1CommandHandler<>));
services.Decorate(typeof(ICommandHandler<>), typeof(Decorator2CommandHandler<>));
//Maybe I should decorate the decorate instead of decorating the commandhandler for a 2nd time?
Each command would have the following:
- (NAME)Command
- (NAME)CommandHandler
- (NAME)CommandSecurityValidator (Decorator)
- (NAME)CommandValidator (Decorator)
Sadly, I can’t get this to work! At the moment of writing I can not tell you the exact errors I am getting, but I think that my scenario isn’t possible.
If it is, please tell me what I am doing wrong! If it is not possible, what would be a good container to get this to work anyway? I have some experience with autofac.
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (2 by maintainers)
Top GitHub Comments
Hey everyone, I managed to get my example to work!
The fix is as follows:
The difference between this bit and the one in my example zip is that now only the commandhandlers that are NOT generic are registered. In my old example the commandhandlers AND the decorators were registered.
The decorators are open generic types but the commandhandlers are closed. That is why the
IsGenericType
works!I hope this helps someone!
#75 #39
I am observing the exact same issue with versions > 2.1.2.
Version 2.1.2 is working fine using open-generics.