question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to scan and decorate an open generic interface used multiple times?

See original GitHub issue

Hello!

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:closed
  • Created 5 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

3reactions
sander1095commented, Apr 17, 2019

Hey everyone, I managed to get my example to work!

The fix is as follows:

//Register all commandhandlers from the commandhandlers project.
// Decorators are not registered because they are open generic types and commandhandlers are closed.
services.Scan(scan =>
      scan.FromAssembliesOf(typeof(ICommandHandler<>))
        .AddClasses(classes => 
        classes.AssignableTo(typeof(ICommandHandler<>)).Where(_ => !_.IsGenericType))
            .AsImplementedInterfaces()
            .WithTransientLifetime());

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

1reaction
fadil-khodabuccus-ckocommented, Jan 4, 2019

I am observing the exact same issue with versions > 2.1.2.

Version 2.1.2 is working fine using open-generics.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How can I scan for generic interfaces?
For example, to find IExample<T> or IExample<string> , search for "IExample`1" . Unlike typeof , nameof cannot be used with an open generic...
Read more >
Advanced Scenarios — Simple Injector 5 documentation
Batch registration of non-generic types based on an open-generic interface; Registering open generic types and working with partially-closed types ...
Read more >
Generic Interfaces - C# Programming Guide
NET class library defines several generic interfaces for use with the collection classes in the System.Collections.Generic namespace.
Read more >
Java Generics Example Tutorial - Generic Method, Class ...
3. Java Generic Interface. Comparable interface is a great example of Generics in interfaces and it's written as: package java.lang; import java ...
Read more >
How to use interfaces and generics in TypeScript - YouTube
In this webinar, Pluralsight author Dan Wahlin will show you the role that interfaces and generics can play in TypeScript and see how...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found